From 5133cb5e2530954a23b93ee22a49273f7333e36b Mon Sep 17 00:00:00 2001 From: Olivier Bertrand <bertrandop@gmail.com> Date: Mon, 3 Feb 2014 16:14:13 +0100 Subject: [PATCH] This is a major update of CONNECT that goes from version 1.1 to 1.2 =================================================================== - Implement a first support of the ALTER TABLE command. This fixes MDEV-5440 but does much more than only that. See the details of how ALTER is supported in the new documentation and also in MDEV-5440 comment. This is done principally by implementing for CONNECT the virtual function check_if_supported_inplace_alter. modified: storage/connect/connect.cc storage/connect/global.h storage/connect/ha_connect.cc storage/connect/ha_connect.h storage/connect/mysql-test/connect/r/bin.result storage/connect/mysql-test/connect/r/csv.result storage/connect/mysql-test/connect/r/dbf.result storage/connect/mysql-test/connect/r/dir.result storage/connect/mysql-test/connect/r/fix.result storage/connect/mysql-test/connect/r/index.result storage/connect/mysql-test/connect/r/ini.result storage/connect/mysql-test/connect/r/occur.result storage/connect/mysql-test/connect/r/pivot.result storage/connect/mysql-test/connect/r/vec.result storage/connect/mysql-test/connect/t/dbf.test storage/connect/plugutil.c storage/connect/user_connect.cc - Fixes the tabname/table_name issue for XML tables. Implement multiple files XML tables. modified: storage/connect/tabxml.cpp storage/connect/tabxml.h - Set to varchar(256) the fields of catalog tables stored as STRBLK's (had length 0 --> CHAR(1)) Add the GetCharString function to the VALBLK class modified: storage/connect/ha_connect.cc storage/connect/valblk.cpp storage/connect/valblk.h storage/connect/value.cpp - Translate CONNECT error messages to system_charset to avoid truncation on not ASCII characters. modified: storage/connect/ha_connect.cc - Update version number modified: storage/connect/ha_connect.cc storage/connect/mysql-test/connect/r/xml.result - Move the TDBASE::data_charset body from xtable.h to table.cpp. (dont' remember why) modified: storage/connect/table.cpp storage/connect/xtable.h - Other modifications are to enhance the support of OEM tables. In particular, they can now provide column definition in dicovery. modified: storage/connect/colblk.h storage/connect/global.h storage/connect/ha_connect.cc storage/connect/mycat.cc storage/connect/plgcnx.h storage/connect/plgdbsem.h storage/connect/xtable.h - Or to add or modify tracing. modified: storage/connect/filamtxt.cpp storage/connect/ha_connect.cc storage/connect/plgdbutl.cpp storage/connect/tabfix.cpp storage/connect/tabmysql.cpp --- storage/connect/colblk.h | 14 +- storage/connect/connect.cc | 2 +- storage/connect/filamtxt.cpp | 12 +- storage/connect/global.h | 3 +- storage/connect/ha_connect.cc | 946 +++++++++++++----- storage/connect/ha_connect.h | 38 +- storage/connect/mycat.cc | 83 ++ .../connect/mysql-test/connect/r/bin.result | 4 - .../connect/mysql-test/connect/r/csv.result | 4 - .../connect/mysql-test/connect/r/dbf.result | 20 +- .../connect/mysql-test/connect/r/dir.result | 2 - .../connect/mysql-test/connect/r/fix.result | 4 - .../connect/mysql-test/connect/r/index.result | 2 - .../connect/mysql-test/connect/r/ini.result | 4 - .../connect/mysql-test/connect/r/occur.result | 2 + .../connect/mysql-test/connect/r/pivot.result | 12 +- .../connect/mysql-test/connect/r/vec.result | 4 - .../connect/mysql-test/connect/r/xml.result | 2 +- storage/connect/mysql-test/connect/t/dbf.test | 14 +- storage/connect/plgcnx.h | 10 +- storage/connect/plgdbsem.h | 22 +- storage/connect/plgdbutl.cpp | 12 +- storage/connect/plugutil.c | 1 + storage/connect/tabfix.cpp | 2 +- storage/connect/table.cpp | 15 +- storage/connect/tabmysql.cpp | 2 +- storage/connect/tabxml.cpp | 61 +- storage/connect/tabxml.h | 1 + storage/connect/user_connect.cc | 1 + storage/connect/valblk.cpp | 45 +- storage/connect/valblk.h | 13 +- storage/connect/value.cpp | 10 +- storage/connect/xtable.h | 18 +- 33 files changed, 1029 insertions(+), 356 deletions(-) diff --git a/storage/connect/colblk.h b/storage/connect/colblk.h index 320350f1923..11fca3e4fb7 100644 --- a/storage/connect/colblk.h +++ b/storage/connect/colblk.h @@ -1,7 +1,7 @@ /*************** Colblk H Declares Source Code File (.H) ***************/ -/* Name: COLBLK.H Version 1.6 */ +/* Name: COLBLK.H Version 1.7 */ /* */ -/* (C) Copyright to the author Olivier BERTRAND 2005-2013 */ +/* (C) Copyright to the author Olivier BERTRAND 2005-2014 */ /* */ /* This file contains the COLBLK and derived classes declares. */ /***********************************************************************/ @@ -99,7 +99,7 @@ class DllExport COLBLK : public XOBJECT { /***********************************************************************/ /* Class SPCBLK: Base class for special column descriptors. */ /***********************************************************************/ -class SPCBLK : public COLBLK { +class DllExport SPCBLK : public COLBLK { public: // Constructor SPCBLK(PCOLUMN cp); @@ -121,7 +121,7 @@ class SPCBLK : public COLBLK { /***********************************************************************/ /* Class RIDBLK: ROWID special column descriptor. */ /***********************************************************************/ -class RIDBLK : public SPCBLK { +class DllExport RIDBLK : public SPCBLK { public: // Constructor RIDBLK(PCOLUMN cp, bool rnm); @@ -140,7 +140,7 @@ class RIDBLK : public SPCBLK { /***********************************************************************/ /* Class FIDBLK: FILEID special column descriptor. */ /***********************************************************************/ -class FIDBLK : public SPCBLK { +class DllExport FIDBLK : public SPCBLK { public: // Constructor FIDBLK(PCOLUMN cp); @@ -161,7 +161,7 @@ class FIDBLK : public SPCBLK { /***********************************************************************/ /* Class TIDBLK: TABID special column descriptor. */ /***********************************************************************/ -class TIDBLK : public SPCBLK { +class DllExport TIDBLK : public SPCBLK { public: // Constructor TIDBLK(PCOLUMN cp); @@ -186,7 +186,7 @@ class TIDBLK : public SPCBLK { /***********************************************************************/ /* Class SIDBLK: SERVID special column descriptor. */ /***********************************************************************/ -class SIDBLK : public SPCBLK { +class DllExport SIDBLK : public SPCBLK { public: // Constructor SIDBLK(PCOLUMN cp); diff --git a/storage/connect/connect.cc b/storage/connect/connect.cc index f3c2559f13e..9340ae97258 100644 --- a/storage/connect/connect.cc +++ b/storage/connect/connect.cc @@ -347,7 +347,7 @@ bool CntOpenTable(PGLOBAL g, PTDB tdbp, MODE mode, char *c1, char *c2, if (xtrace) printf("About to open the table: tdbp=%p\n", tdbp); - if (mode != MODE_ANY) { + if (mode != MODE_ANY && mode != MODE_ALTER) { if (tdbp->OpenDB(g)) { printf("%s\n", g->Message); return true; diff --git a/storage/connect/filamtxt.cpp b/storage/connect/filamtxt.cpp index 2291f2c2b00..1d3f17e2228 100644 --- a/storage/connect/filamtxt.cpp +++ b/storage/connect/filamtxt.cpp @@ -535,7 +535,7 @@ int DOSFAM::ReadBuffer(PGLOBAL g) if (!Stream) return RC_EF; - if (trace) + if (trace > 1) htrc("ReadBuffer: Tdbp=%p To_Line=%p Placed=%d\n", Tdbp, Tdbp->To_Line, Placed); @@ -548,20 +548,20 @@ int DOSFAM::ReadBuffer(PGLOBAL g) CurBlk = (int)Rows++; - if (trace) + if (trace > 1) htrc("ReadBuffer: CurBlk=%d\n", CurBlk); } else Placed = false; - if (trace) + if (trace > 1) htrc(" About to read: stream=%p To_Buf=%p Buflen=%d\n", Stream, To_Buf, Buflen); if (fgets(To_Buf, Buflen, Stream)) { p = To_Buf + strlen(To_Buf) - 1; - if (trace) + if (trace > 1) htrc(" Read: To_Buf=%p p=%c\n", To_Buf, To_Buf, p); #if defined(UNIX) @@ -589,7 +589,7 @@ int DOSFAM::ReadBuffer(PGLOBAL g) } else if (*p == '\n') *p = '\0'; // Eliminate ending new-line character - if (trace) + if (trace > 1) htrc(" To_Buf='%s'\n", To_Buf); strcpy(Tdbp->To_Line, To_Buf); @@ -610,7 +610,7 @@ int DOSFAM::ReadBuffer(PGLOBAL g) rc = RC_FX; } // endif's fgets - if (trace) + if (trace > 1) htrc("ReadBuffer: rc=%d\n", rc); IsRead = true; diff --git a/storage/connect/global.h b/storage/connect/global.h index 4c0bc993123..8bccd742a64 100644 --- a/storage/connect/global.h +++ b/storage/connect/global.h @@ -219,9 +219,10 @@ typedef struct _global { /* Global structure */ uint Sarea_Size; /* Work area size */ PACTIVITY Activityp, ActivityStart; char Message[MAX_STR]; - short Trace; int Createas; /* To pass info to created table */ void *Xchk; /* indexes in create/alter */ + short Alchecked; /* Checked for ALTER */ + short Trace; int jump_level; jmp_buf jumper[MAX_JUMP + 2]; } GLOBAL; diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index d051ef76698..4533c628686 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -1,4 +1,4 @@ -/* Copyright (C) Olivier Bertrand 2004 - 2013 +/* Copyright (C) Olivier Bertrand 2004 - 2014 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -107,6 +107,7 @@ #include "field.h" #include "sql_parse.h" #include "sql_base.h" +#include <sys/stat.h> #if defined(NEW_WAY) #include "sql_table.h" #endif // NEW_WAY @@ -164,8 +165,13 @@ extern "C" char plgini[]; extern "C" char nmfile[]; extern "C" char pdebug[]; +/***********************************************************************/ +/* Initialize the ha_connect static members. */ +/***********************************************************************/ +#define CONNECT_INI "connect.ini" extern "C" { - char version[]= "Version 1.01.0011 December 15, 2013"; + char connectini[_MAX_PATH]= CONNECT_INI; + char version[]= "Version 1.02.0001 February 03, 2014"; #if defined(XMSG) char msglang[]; // Default message language @@ -173,17 +179,17 @@ extern "C" { int trace= 0; // The general trace value } // extern "C" -/****************************************************************************/ -/* Initialize the ha_connect static members. */ -/****************************************************************************/ -#define CONNECT_INI "connect.ini" -char connectini[_MAX_PATH]= CONNECT_INI; int xtrace= 0; ulong ha_connect::num= 0; //int DTVAL::Shift= 0; +/***********************************************************************/ +/* Utility functions. */ +/***********************************************************************/ +PQRYRES OEMColumns(PGLOBAL g, PTOS topt, char *tab, char *db, bool info); + static PCONNECT GetUser(THD *thd, PCONNECT xp); -static PGLOBAL GetPlug(THD *thd, PCONNECT& lxp); +static PGLOBAL GetPlug(THD *thd, PCONNECT& lxp); static handler *connect_create_handler(handlerton *hton, TABLE_SHARE *table, @@ -474,6 +480,7 @@ ha_connect::ha_connect(handlerton *hton, TABLE_SHARE *table_arg) valid_query_id= 0; creat_query_id= (table && table->in_use) ? table->in_use->query_id : 0; stop= false; + alter= false; indexing= -1; locked= 0; data_file_name= NULL; @@ -491,6 +498,11 @@ ha_connect::ha_connect(handlerton *hton, TABLE_SHARE *table_arg) /****************************************************************************/ ha_connect::~ha_connect(void) { + if (xtrace) + printf("Delete CONNECT %p, table: %s, xp=%p count=%d\n", this, + table ? table->s->table_name.str : "<null>", + xp, xp ? xp->count : 0); + if (xp) { PCONNECT p; @@ -562,12 +574,55 @@ static PGLOBAL GetPlug(THD *thd, PCONNECT& lxp) return (lxp) ? lxp->g : NULL; } // end of GetPlug +/****************************************************************************/ +/* Get the implied table type. */ +/****************************************************************************/ +TABTYPE ha_connect::GetRealType(PTOS pos) +{ + TABTYPE type= GetTypeID(pos->type); + + if (type == TAB_UNDEF) + type= pos->srcdef ? TAB_MYSQL : pos->tabname ? TAB_PRX : TAB_DOS; + + return type; +} // end of GetRealType + +/** @brief + This is a list of flags that indicate what functionality the storage + engine implements. The current table flags are documented in handler.h +*/ +ulonglong ha_connect::table_flags() const +{ + ulonglong flags= HA_NO_TRANSACTIONS | HA_REC_NOT_IN_SEQ | + HA_NO_AUTO_INCREMENT | HA_NO_PREFIX_CHAR_KEYS | + HA_HAS_RECORDS | HA_CAN_VIRTUAL_COLUMNS | + HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE | +// HA_NULL_IN_KEY | not implemented yet + HA_DUPLICATE_KEY_NOT_IN_ORDER | + HA_MUST_USE_TABLE_CONDITION_PUSHDOWN; + ha_connect *hp= (ha_connect*)this; + PTOS pos= hp->GetTableOptionStruct(table); + + if (pos) { + TABTYPE type= hp->GetRealType(pos); + + if (IsFileType(type)) + flags|= HA_FILE_BASED; + + // No data change on ALTER for outward tables + if (!IsFileType(type) || hp->FileExists(pos->filename)) + flags|= HA_NO_COPY_ON_ALTER; + + } // endif pos + + return flags; +} // end of table_flags /****************************************************************************/ /* Return the value of an option specified in the option list. */ /****************************************************************************/ -static char *GetListOption(PGLOBAL g, const char *opname, - const char *oplist, const char *def=NULL) +char *GetListOption(PGLOBAL g, const char *opname, + const char *oplist, const char *def) { char key[16], val[256]; char *pk, *pv, *pn; @@ -619,7 +674,8 @@ static char *GetListOption(PGLOBAL g, const char *opname, /****************************************************************************/ PTOS ha_connect::GetTableOptionStruct(TABLE *tab) { - return (tshp) ? tshp->option_struct : tab->s->option_struct; + return (tshp) ? tshp->option_struct : + (tab) ? tab->s->option_struct : NULL; } // end of GetTableOptionStruct /****************************************************************************/ @@ -972,24 +1028,27 @@ void *ha_connect::GetColumnOption(PGLOBAL g, void *field, PCOLINFO pcf) /****************************************************************************/ /* Returns the index description structure used to make the index. */ /****************************************************************************/ -PIXDEF ha_connect::GetIndexInfo(void) +PIXDEF ha_connect::GetIndexInfo(TABLE_SHARE *s) { char *name, *pn; bool unique; PIXDEF xdp, pxd=NULL, toidx= NULL; PKPDEF kpp, pkp; - PGLOBAL& g= xp->g; KEY kp; + PGLOBAL& g= xp->g; - for (int n= 0; (unsigned)n < table->s->keynames.count; n++) { + if (!s) + s= table->s; + + for (int n= 0; (unsigned)n < s->keynames.count; n++) { if (xtrace) printf("Getting created index %d info\n", n + 1); // Find the index to describe - kp= table->s->key_info[n]; + kp= s->key_info[n]; // Now get index information - pn= (char*)table->s->keynames.type_names[n]; + pn= (char*)s->keynames.type_names[n]; name= (char*)PlugSubAlloc(g, NULL, strlen(pn) + 1); strcpy(name, pn); // This is probably unuseful unique= (kp.flags & 1) != 0; @@ -1292,7 +1351,7 @@ int ha_connect::MakeRecord(char *buf) if (fp->vcol_info && !fp->stored_in_db) continue; // This is a virtual column - if (bitmap_is_set(map, fp->field_index)) { + if (bitmap_is_set(map, fp->field_index) || alter) { // This is a used field, fill the buffer with value for (colp= tdbp->GetColumns(); colp; colp= colp->GetNext()) if (!stricmp(colp->GetName(), (char*)fp->field_name)) @@ -1457,18 +1516,17 @@ int ha_connect::ScanRecord(PGLOBAL g, uchar *buf) break; default: fp->val_str(&attribute); - if (charset == &my_charset_bin) - { - value->SetValue_psz(attribute.c_ptr_safe()); - } - else - { + + if (charset != &my_charset_bin) { // Convert from SQL field charset to DATA_CHARSET uint cnv_errors; + data_charset_value.copy(attribute.ptr(), attribute.length(), attribute.charset(), charset, &cnv_errors); value->SetValue_psz(data_charset_value.c_ptr_safe()); - } + } else + value->SetValue_psz(attribute.c_ptr_safe()); + break; } // endswitch Type @@ -1598,7 +1656,7 @@ PFIL ha_connect::CheckCond(PGLOBAL g, PFIL filp, AMT tty, Item *cond) if (!cond) return NULL; - if (xtrace > 1) + if (xtrace) printf("Cond type=%d\n", cond->type()); if (cond->type() == COND::COND_ITEM) { @@ -1608,7 +1666,7 @@ PFIL ha_connect::CheckCond(PGLOBAL g, PFIL filp, AMT tty, Item *cond) if (x) return NULL; - if (xtrace > 1) + if (xtrace) printf("Cond: Ftype=%d name=%s\n", cond_item->functype(), cond_item->func_name()); @@ -1655,7 +1713,7 @@ PFIL ha_connect::CheckCond(PGLOBAL g, PFIL filp, AMT tty, Item *cond) Item_func *condf= (Item_func *)cond; Item* *args= condf->arguments(); - if (xtrace > 1) + if (xtrace) printf("Func type=%d argnum=%d\n", condf->functype(), condf->argument_count()); @@ -1684,11 +1742,11 @@ PFIL ha_connect::CheckCond(PGLOBAL g, PFIL filp, AMT tty, Item *cond) return NULL; for (i= 0; i < condf->argument_count(); i++) { - if (xtrace > 1) + if (xtrace) printf("Argtype(%d)=%d\n", i, args[i]->type()); if (i >= 2 && !ismul) { - if (xtrace > 1) + if (xtrace) printf("Unexpected arg for vop=%d\n", vop); continue; @@ -1710,6 +1768,8 @@ PFIL ha_connect::CheckCond(PGLOBAL g, PFIL filp, AMT tty, Item *cond) if (fop && fop->special) { if (tty == TYPE_AM_TBL && !stricmp(fop->special, "TABID")) fnm= "TABID"; + else if (tty == TYPE_AM_PLG) + fnm= fop->special; else return NULL; @@ -1718,7 +1778,7 @@ PFIL ha_connect::CheckCond(PGLOBAL g, PFIL filp, AMT tty, Item *cond) else fnm= pField->field->field_name; - if (xtrace > 1) { + if (xtrace) { printf("Field index=%d\n", pField->field->field_index); printf("Field name=%s\n", pField->field->field_name); } // endif xtrace @@ -1728,15 +1788,36 @@ PFIL ha_connect::CheckCond(PGLOBAL g, PFIL filp, AMT tty, Item *cond) return NULL; strcat(body, fnm); + } else if (args[i]->type() == COND::FUNC_ITEM) { + if (tty == TYPE_AM_MYSQL) { + if (!CheckCond(g, filp, tty, args[i])) + return NULL; + + } else + return NULL; + } else { char buff[256]; String *res, tmp(buff, sizeof(buff), &my_charset_bin); Item_basic_constant *pval= (Item_basic_constant *)args[i]; + switch (args[i]->type()) { + case COND::STRING_ITEM: + case COND::INT_ITEM: + case COND::REAL_ITEM: + case COND::NULL_ITEM: + case COND::DECIMAL_ITEM: + case COND::DATE_ITEM: + case COND::CACHE_ITEM: + break; + default: + return NULL; + } // endswitch type + if ((res= pval->val_str(&tmp)) == NULL) return NULL; // To be clarified - if (xtrace > 1) + if (xtrace) printf("Value=%.*s\n", res->length(), res->ptr()); // IN and BETWEEN clauses should be col VOP list @@ -1781,7 +1862,7 @@ PFIL ha_connect::CheckCond(PGLOBAL g, PFIL filp, AMT tty, Item *cond) filp->Op= vop; } else { - if (xtrace > 1) + if (xtrace) printf("Unsupported condition\n"); return NULL; @@ -1819,7 +1900,8 @@ const COND *ha_connect::cond_push(const COND *cond) bool x= (tty == TYPE_AM_MYX || tty == TYPE_AM_XDBC); if (tty == TYPE_AM_WMI || tty == TYPE_AM_ODBC || - tty == TYPE_AM_TBL || tty == TYPE_AM_MYSQL || x) { + tty == TYPE_AM_TBL || tty == TYPE_AM_MYSQL || + tty == TYPE_AM_PLG || x) { PGLOBAL& g= xp->g; PFIL filp= (PFIL)PlugSubAlloc(g, NULL, sizeof(FILTER)); @@ -1830,7 +1912,7 @@ const COND *ha_connect::cond_push(const COND *cond) if (CheckCond(g, filp, tty, (Item *)cond)) { if (xtrace) - puts(filp->Body); + printf("cond_push: %s\n", filp->Body); if (!x) PlugSubAlloc(g, NULL, strlen(filp->Body) + 1); @@ -1879,9 +1961,19 @@ bool ha_connect::get_error_message(int error, String* buf) { DBUG_ENTER("ha_connect::get_error_message"); - if (xp && xp->g) - buf->copy(xp->g->Message, (uint)strlen(xp->g->Message), - system_charset_info); + if (xp && xp->g) { + PGLOBAL g= xp->g; + char *msg= (char*)PlugSubAlloc(g, NULL, strlen(g->Message) * 3); + uint dummy_errors; + uint32 len= copy_and_convert(msg, strlen(g->Message) * 3, + system_charset_info, + g->Message, strlen(g->Message), + &my_charset_latin1, + &dummy_errors); + msg[len]= '\0'; + buf->copy(msg, (uint)strlen(msg), system_charset_info); + } else + buf->copy("Cannot retrieve msg", 19, system_charset_info); DBUG_RETURN(false); } // end of get_error_message @@ -2030,6 +2122,10 @@ int ha_connect::write_row(uchar *buf) PGLOBAL& g= xp->g; DBUG_ENTER("ha_connect::write_row"); + // This is not tested yet + if (xmod == MODE_ALTER) + xmod= MODE_INSERT; + // Open the table if it was not opened yet (locked) if (!IsOpened() || xmod != tdbp->GetMode()) { if (IsOpened()) @@ -2155,6 +2251,9 @@ int ha_connect::index_init(uint idx, bool sorted) PGLOBAL& g= xp->g; DBUG_ENTER("index_init"); + if (xtrace) + printf("index_init: this=%p idx=%u sorted=%d\n", this, idx, sorted); + if ((rc= rnd_init(0))) return rc; @@ -2184,6 +2283,10 @@ int ha_connect::index_init(uint idx, bool sorted) rc= 0; } // endif indexing + if (xtrace) + printf("index_init: rc=%d indexing=%d active_index=%d\n", + rc, indexing, active_index); + DBUG_RETURN(rc); } // end of index_init @@ -2406,8 +2509,15 @@ int ha_connect::rnd_init(bool scan) (xp) ? xp->g : NULL); DBUG_ENTER("ha_connect::rnd_init"); + // This is not tested yet + if (xmod == MODE_ALTER) { + xmod= MODE_READ; + alter= 1; + } // endif xmod + if (xtrace) - printf("%p in rnd_init: scan=%d\n", this, scan); + printf("rnd_init: this=%p scan=%d xmod=%d alter=%d\n", + this, scan, xmod, alter); if (!g || !table || xmod == MODE_INSERT) DBUG_RETURN(HA_ERR_INITIALIZATION); @@ -2632,7 +2742,8 @@ int ha_connect::info(uint flag) if (!valid_info) { // tdbp must be available to get updated info if (xp->CheckQuery(valid_query_id) || !tdbp) { - if (xmod == MODE_ANY) { // Pure info, not a query + if (xmod == MODE_ANY || xmod == MODE_ALTER) { + // Pure info, not a query pure= true; xp->CheckCleanup(); } // endif xmod @@ -2752,19 +2863,9 @@ int ha_connect::delete_all_rows() bool ha_connect::check_privileges(THD *thd, PTOS options, char *dbn) { const char *db= (dbn && *dbn) ? dbn : NULL; + TABTYPE type=GetRealType(options); - if (!options->type) { - if (options->srcdef) - options->type= "MYSQL"; - else if (options->tabname) - options->type= "PROXY"; - else - options->type= "DOS"; - - } // endif type - - switch (GetTypeID(options->type)) - { + switch (type) { case TAB_UNDEF: // case TAB_CATLG: case TAB_PLG: @@ -2784,18 +2885,30 @@ bool ha_connect::check_privileges(THD *thd, PTOS options, char *dbn) case TAB_XML: case TAB_INI: case TAB_VEC: - if (!options->filename) + if (options->filename && *options->filename) { + char *s, path[FN_REFLEN], dbpath[FN_REFLEN]; +#if defined(WIN32) + s= "\\"; +#else // !WIN32 + s= "/"; +#endif // !WIN32 + strcpy(dbpath, mysql_real_data_home); + + if (db) + strcat(strcat(dbpath, db), s); + + (void) fn_format(path, options->filename, dbpath, "", + MY_RELATIVE_PATH | MY_UNPACK_FILENAME); + + if (!is_secure_file_path(path)) { + my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv"); + return true; + } // endif path + + } else return false; - char path[FN_REFLEN]; - (void) fn_format(path, options->filename, mysql_real_data_home, "", - MY_RELATIVE_PATH | MY_UNPACK_FILENAME); - if (!is_secure_file_path(path)) - { - my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv"); - return true; - } - /* Fall through to check FILE_ACL */ + /* Fall through to check FILE_ACL */ case TAB_ODBC: case TAB_MYSQL: case TAB_DIR: @@ -2811,7 +2924,7 @@ bool ha_connect::check_privileges(THD *thd, PTOS options, char *dbn) case TAB_OCCUR: case TAB_PIVOT: return false; - } + } // endswitch type my_printf_error(ER_UNKNOWN_ERROR, "check_privileges failed", MYF(0)); return true; @@ -2883,7 +2996,6 @@ MODE ha_connect::CheckMode(PGLOBAL g, THD *thd, break; case SQLCOM_DROP_TABLE: case SQLCOM_RENAME_TABLE: - case SQLCOM_ALTER_TABLE: newmode= MODE_ANY; break; case SQLCOM_DROP_INDEX: @@ -2895,6 +3007,9 @@ MODE ha_connect::CheckMode(PGLOBAL g, THD *thd, case SQLCOM_DROP_VIEW: newmode= MODE_ANY; break; + case SQLCOM_ALTER_TABLE: + newmode= MODE_ALTER; + break; default: printf("Unsupported sql_command=%d", thd_sql_command(thd)); strcpy(g->Message, "CONNECT Unsupported command"); @@ -2926,7 +3041,6 @@ MODE ha_connect::CheckMode(PGLOBAL g, THD *thd, break; case SQLCOM_DROP_INDEX: case SQLCOM_CREATE_INDEX: - case SQLCOM_ALTER_TABLE: *chk= true; // stop= true; case SQLCOM_DROP_TABLE: @@ -2937,6 +3051,10 @@ MODE ha_connect::CheckMode(PGLOBAL g, THD *thd, case SQLCOM_DROP_VIEW: newmode= MODE_ANY; break; + case SQLCOM_ALTER_TABLE: + *chk= true; + newmode= MODE_ALTER; + break; default: printf("Unsupported sql_command=%d", thd_sql_command(thd)); strcpy(g->Message, "CONNECT Unsupported command"); @@ -3023,7 +3141,8 @@ int ha_connect::external_lock(THD *thd, int lock_type) DBUG_ASSERT(thd == current_thd); if (xtrace) - printf("%p external_lock: lock_type=%d\n", this, lock_type); + printf("external_lock: this=%p thd=%p xp=%d g=%p lock_type=%d\n", + this, thd, xp, g, lock_type); if (!g) DBUG_RETURN(HA_ERR_INTERNAL_ERROR); @@ -3043,13 +3162,17 @@ int ha_connect::external_lock(THD *thd, int lock_type) } // endswitch mode if (newmode == MODE_ANY) { + int sqlcom= thd_sql_command(thd); + // This is unlocking, do it by closing the table - if (xp->CheckQueryID() && thd_sql_command(thd) != SQLCOM_UNLOCK_TABLES - && thd_sql_command(thd) != SQLCOM_LOCK_TABLES) + if (xp->CheckQueryID() && sqlcom != SQLCOM_UNLOCK_TABLES + && sqlcom != SQLCOM_LOCK_TABLES) rc= 2; // Logical error ??? - else if (g->Xchk) { - if (!tdbp || *tdbp->GetName() == '#') { - if (!tdbp && !(tdbp= GetTDB(g))) +// else if (g->Xchk && (sqlcom == SQLCOM_CREATE_INDEX || +// sqlcom == SQLCOM_DROP_INDEX)) { + else if (g->Xchk) { + if (!tdbp) { + if (!(tdbp= GetTDB(g))) DBUG_RETURN(HA_ERR_INTERNAL_ERROR); else if (!((PTDBASE)tdbp)->GetDef()->Indexable()) { sprintf(g->Message, "external_lock: Table %s is not indexable", tdbp->GetName()); @@ -3132,31 +3255,21 @@ int ha_connect::external_lock(THD *thd, int lock_type) if (adp) // Here we do make the new indexes if (tdp->MakeIndex(g, adp, true) == RC_FX) { -//#if defined(_DEBUG) - // Make it a warning to avoid crash on debug + // Make it a warning to avoid crash 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 } // endif MakeIndex - } // endif Mode + } // endif Tdbp } // endelse Xchk if (CloseTable(g)) { // This is an error while builing index -//#if defined(_DEBUG) - // Make it a warning to avoid crash on debug + // Make it a warning to avoid crash 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 } // endif Close locked= 0; @@ -3183,19 +3296,32 @@ int ha_connect::external_lock(THD *thd, int lock_type) valid_info= false; } // endif CheckCleanup +#if 0 if (xcheck) { // This must occur after CheckCleanup - g->Xchk= new(g) XCHK; - ((PCHK)g->Xchk)->oldsep= GetBooleanOption("Sepindex", false); - ((PCHK)g->Xchk)->oldpix= GetIndexInfo(); + if (!g->Xchk) { + g->Xchk= new(g) XCHK; + ((PCHK)g->Xchk)->oldsep= GetBooleanOption("Sepindex", false); + ((PCHK)g->Xchk)->oldpix= GetIndexInfo(); + } // endif Xchk + } else g->Xchk= NULL; +#endif // 0 if (cras) g->Createas= 1; // To tell created table to ignore FLAG - if (xtrace) - printf("Calling CntCheckDB db=%s\n", GetDBName(NULL)); + if (xtrace) { +#if 0 + printf("xcheck=%d cras=%d\n", xcheck, cras); + + if (xcheck) + printf("oldsep=%d oldpix=%p\n", + ((PCHK)g->Xchk)->oldsep, ((PCHK)g->Xchk)->oldpix); +#endif // 0 + printf("Calling CntCheckDB db=%s cras=%d\n", GetDBName(NULL), cras); + } // endif xtrace // Set or reset the good database environment if (CntCheckDB(g, this, GetDBName(NULL))) { @@ -3212,7 +3338,7 @@ int ha_connect::external_lock(THD *thd, int lock_type) else tdbp= NULL; - }// endif tdbp + } // endif tdbp xmod= newmode; @@ -3330,7 +3456,6 @@ filename_to_dbname_and_tablename(const char *filename, return false; } // end of filename_to_dbname_and_tablename - /** @brief Used to delete or rename a table. By the time delete_table() has been @@ -3355,55 +3480,86 @@ filename_to_dbname_and_tablename(const char *filename, int ha_connect::delete_or_rename_table(const char *name, const char *to) { DBUG_ENTER("ha_connect::delete_or_rename_table"); - /* We have to retrieve the information about this table options. */ - ha_table_option_struct *pos; - char key[MAX_DBKEY_LENGTH], db[128], tabname[128]; - int rc= 0; - uint key_length; - TABLE_SHARE *share; - THD *thd= current_thd; + char db[128], tabname[128]; + int rc= 0; + bool ok= false; + THD *thd= current_thd; + int sqlcom= thd_sql_command(thd); + + if (xtrace) { + if (to) + printf("rename_table: this=%p thd=%p sqlcom=%d from=%s to=%s\n", + this, thd, sqlcom, name, to); + else + printf("delete_table: this=%p thd=%p sqlcom=%d name=%s\n", + this, thd, sqlcom, name); + + } // endif xtrace if (to && (filename_to_dbname_and_tablename(to, db, sizeof(db), - tabname, sizeof(tabname)) || - *tabname == '#')) - goto fin; + tabname, sizeof(tabname)) + || (*tabname == '#' && sqlcom == SQLCOM_CREATE_INDEX))) + DBUG_RETURN(0); if (filename_to_dbname_and_tablename(name, db, sizeof(db), - tabname, sizeof(tabname)) || - *tabname == '#') - goto fin; + tabname, sizeof(tabname)) + || (*tabname == '#' && sqlcom == SQLCOM_CREATE_INDEX)) + DBUG_RETURN(0); - key_length= tdc_create_key(key, db, tabname); + // If a temporary file exists, all the tests below were passed + // successfully when making it, so they are not needed anymore + // in particular because they sometimes cause DBUG_ASSERT crash. + if (*tabname != '#') { + // We have to retrieve the information about this table options. + ha_table_option_struct *pos; + char key[MAX_DBKEY_LENGTH]; + uint key_length; + TABLE_SHARE *share; - // share contains the option struct that we need - if (!(share= alloc_table_share(db, tabname, key, key_length))) - goto fin; + key_length= tdc_create_key(key, db, tabname); - // Get the share info from the .frm file - if (open_table_def(thd, share)) - goto err; + // share contains the option struct that we need + if (!(share= alloc_table_share(db, tabname, key, key_length))) + DBUG_RETURN(rc); - // Now we can work - pos= share->option_struct; +#if 0 + if (*tabname == '#') { + // These are in ???? charset after renaming + char *p= strchr(share->path.str, '@'); + strcpy(p, share->table_name.str); + share->path.length= strlen(share->path.str); + share->normalized_path.length= share->path.length; + } // endif tabname +#endif // 0 + + // Get the share info from the .frm file + if (!open_table_def(thd, share)) { + // Now we can work + if ((pos= share->option_struct)) { + if (check_privileges(thd, pos, db)) + rc= HA_ERR_INTERNAL_ERROR; // ??? + else + if (IsFileType(GetRealType(pos)) && !pos->filename) + ok= true; + + } // endif pos + + } else // Avoid infamous DBUG_ASSERT + thd->get_stmt_da()->reset_diagnostics_area(); - if (check_privileges(thd, pos, db)) - { free_table_share(share); - DBUG_RETURN(HA_ERR_INTERNAL_ERROR); - } + } else // Temporary file + ok= true; - if (IsFileType(GetTypeID(pos->type)) && !pos->filename) { + if (ok) { // Let the base handler do the job if (to) rc= handler::rename_table(name, to); - else - rc= handler::delete_table(name); - } // endif filename + else if ((rc= handler::delete_table(name)) == ENOENT) + rc= 0; // No files is not an error for CONNECT + + } // endif ok - // Done no more need for this - err: - free_table_share(share); - fin: DBUG_RETURN(rc); } // end of delete_or_rename_table @@ -4113,6 +4269,13 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, else ok= true; + break; + case TAB_OEM: + if (topt->module && topt->subtype) + ok= true; + else + strcpy(g->Message, "Missing OEM module or subtype"); + break; default: sprintf(g->Message, "Cannot get column info for table type %s", topt->type); @@ -4217,6 +4380,9 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, case TAB_PIVOT: qrp= PivotColumns(g, tab, src, pic, fcl, host, db, user, pwd, port); break; + case TAB_OEM: + qrp= OEMColumns(g, topt, tab, (char*)db, fnc == FNC_COL); + break; default: strcpy(g->Message, "System error during assisted discovery"); break; @@ -4236,6 +4402,9 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, dec= crp->Prec; flg= crp->Flag; + if (!len && typ == TYPE_STRING) + len= 256; // STRBLK's have 0 length + #if defined(NEW_WAY) // Now add the field rc= add_fields(g, thd, &alter_info, cnm, typ, len, dec, @@ -4422,8 +4591,15 @@ int ha_connect::create(const char *name, TABLE *table_arg, PGLOBAL g= xp->g; DBUG_ENTER("ha_connect::create"); + int sqlcom= thd_sql_command(table_arg->in_use); PTOS options= GetTableOptionStruct(table_arg); + table= table_arg; // Used by called functions + + if (xtrace) + printf("create: this=%p thd=%p xp=%p g=%p sqlcom=%d name=%s\n", + this, thd, xp, g, sqlcom, GetTableName()); + // CONNECT engine specific table options: DBUG_ASSERT(options); type= GetTypeID(options->type); @@ -4682,83 +4858,89 @@ int ha_connect::create(const char *name, TABLE *table_arg, } // endfor field - table= table_arg; // Used by called functions - - if (IsFileType(type)) { - if (!options->filename) { - // The file name is not specified, create a default file in - // the database directory named table_name.table_type. - // (temporarily not done for XML because a void file causes - // the XML parsers to report an error on the first Insert) - char buf[256], fn[_MAX_PATH], dbpath[128], lwt[12]; - int h; - - strcpy(buf, GetTableName()); - - if (*buf != '#') { - // Check for incompatible options - if (options->sepindex) { - my_message(ER_UNKNOWN_ERROR, - "SEPINDEX is incompatible with unspecified file name", - MYF(0)); - DBUG_RETURN(HA_ERR_UNSUPPORTED); - } else if (GetTypeID(options->type) == TAB_VEC) - if (!table->s->max_rows || options->split) { - my_printf_error(ER_UNKNOWN_ERROR, - "%s tables whose file name is unspecified cannot be split", - MYF(0), options->type); - DBUG_RETURN(HA_ERR_UNSUPPORTED); - } else if (options->header == 2) { - my_printf_error(ER_UNKNOWN_ERROR, - "header=2 is not allowed for %s tables whose file name is unspecified", - MYF(0), options->type); - DBUG_RETURN(HA_ERR_UNSUPPORTED); - } // endif's - - // Fold type to lower case - for (int i= 0; i < 12; i++) - if (!options->type[i]) { - lwt[i]= 0; - break; - } else - lwt[i]= tolower(options->type[i]); - - strcat(strcat(buf, "."), lwt); - sprintf(g->Message, "No file name. Table will use %s", buf); - push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message); - strcat(strcat(strcpy(dbpath, "./"), table->s->db.str), "/"); - PlugSetPath(fn, buf, dbpath); + if ((sqlcom == SQLCOM_CREATE_TABLE || *GetTableName() == '#') + && IsFileType(type) && !options->filename) { + // The file name is not specified, create a default file in + // the database directory named table_name.table_type. + // (temporarily not done for XML because a void file causes + // the XML parsers to report an error on the first Insert) + char buf[256], fn[_MAX_PATH], dbpath[128], lwt[12]; + int h; + + strcpy(buf, GetTableName()); + + // Check for incompatible options + if (options->sepindex) { + my_message(ER_UNKNOWN_ERROR, + "SEPINDEX is incompatible with unspecified file name", + MYF(0)); + DBUG_RETURN(HA_ERR_UNSUPPORTED); + } else if (GetTypeID(options->type) == TAB_VEC) + if (!table->s->max_rows || options->split) { + my_printf_error(ER_UNKNOWN_ERROR, + "%s tables whose file name is unspecified cannot be split", + MYF(0), options->type); + DBUG_RETURN(HA_ERR_UNSUPPORTED); + } else if (options->header == 2) { + my_printf_error(ER_UNKNOWN_ERROR, + "header=2 is not allowed for %s tables whose file name is unspecified", + MYF(0), options->type); + DBUG_RETURN(HA_ERR_UNSUPPORTED); + } // endif's + + // Fold type to lower case + for (int i= 0; i < 12; i++) + if (!options->type[i]) { + lwt[i]= 0; + break; + } else + lwt[i]= tolower(options->type[i]); - if ((h= ::open(fn, O_CREAT | O_EXCL, 0666)) == -1) { - if (errno == EEXIST) - sprintf(g->Message, "Default file %s already exists", fn); - else - sprintf(g->Message, "Error %d creating file %s", errno, fn); - - push_warning(table->in_use, - Sql_condition::WARN_LEVEL_WARN, 0, g->Message); - } else - ::close(h); + strcat(strcat(buf, "."), lwt); + sprintf(g->Message, "No file name. Table will use %s", buf); + push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message); + strcat(strcat(strcpy(dbpath, "./"), table->s->db.str), "/"); + PlugSetPath(fn, buf, dbpath); - if (type == TAB_FMT || options->readonly) - push_warning(table->in_use, Sql_condition::WARN_LEVEL_WARN, 0, - "Congratulation, you just created a read-only void table!"); + if ((h= ::open(fn, O_CREAT | O_EXCL, 0666)) == -1) { + if (errno == EEXIST) + sprintf(g->Message, "Default file %s already exists", fn); + else + sprintf(g->Message, "Error %d creating file %s", errno, fn); - } // endif buf + push_warning(table->in_use, + Sql_condition::WARN_LEVEL_WARN, 0, g->Message); + } else + ::close(h); + + if (type == TAB_FMT || options->readonly) + push_warning(table->in_use, Sql_condition::WARN_LEVEL_WARN, 0, + "Congratulation, you just created a read-only void table!"); - } // endif filename + } // endif - } // endif type + if (xtrace) + printf("xchk=%d createas=%d\n", g->Xchk, g->Createas); - // To check whether indexes have to be made or remade + // To check whether indices have to be made or remade if (!g->Xchk) { PIXDEF xdp; - // We should be in CREATE TABLE - if (thd_sql_command(table->in_use) != SQLCOM_CREATE_TABLE) + // We should be in CREATE TABLE or ALTER_TABLE + if (sqlcom != SQLCOM_CREATE_TABLE && sqlcom != SQLCOM_ALTER_TABLE) push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, "Wrong command in create, please contact CONNECT team"); + if (sqlcom == SQLCOM_ALTER_TABLE && g->Alchecked == 0 && + (!IsFileType(type) || FileExists(options->filename))) { + // This is an ALTER to CONNECT from another engine. + // It cannot be accepted because the table data would be lost + // except when the target file does not exist. + strcpy(g->Message, "Operation denied. Table data would be lost."); + my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0)); + DBUG_RETURN(HA_ERR_INTERNAL_ERROR); + } // endif outward + // Get the index definitions if (xdp= GetIndexInfo()) { if (IsTypeIndexable(type)) { @@ -4786,7 +4968,13 @@ int ha_connect::create(const char *name, TABLE *table_arg, } // endif xdp } else { + // This should not happen anymore with indexing new way + my_message(ER_UNKNOWN_ERROR, + "CONNECT index modification should be in-place", MYF(0)); + DBUG_RETURN(HA_ERR_UNSUPPORTED); +#if 0 PIXDEF xdp= GetIndexInfo(); + PCHK xcp= (PCHK)g->Xchk; if (xdp) { if (!IsTypeIndexable(type)) { @@ -4795,19 +4983,356 @@ int ha_connect::create(const char *name, TABLE *table_arg, my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0)); rc= HA_ERR_INTERNAL_ERROR; } else { - ((PCHK)g->Xchk)->newpix= xdp; - ((PCHK)g->Xchk)->newsep= GetBooleanOption("Sepindex", false); + xcp->newpix= xdp; + xcp->newsep= GetBooleanOption("Sepindex", false); } // endif Indexable - } else if (!((PCHK)g->Xchk)->oldpix) + } else if (!xcp->oldpix) g->Xchk= NULL; + if (xtrace && g->Xchk) + printf("oldsep=%d newsep=%d oldpix=%p newpix=%p\n", + xcp->oldsep, xcp->newsep, xcp->oldpix, xcp->newpix); + +// if (g->Xchk && +// (sqlcom != SQLCOM_CREATE_INDEX && sqlcom != SQLCOM_DROP_INDEX)) { + if (g->Xchk) { + PIXDEF xp1, xp2; + bool b= false; // true if index changes + + if (xcp->oldsep == xcp->newsep) { + for (xp1= xcp->newpix, xp2= xcp->oldpix; + xp1 || xp2; + xp1= xp1->Next, xp2= xp2->Next) + if (!xp1 || !xp2 || !IsSameIndex(xp1, xp2)) { + b= true; + break; + } // endif xp1 + + } else + b= true; + + if (!b) + g->Xchk= NULL; + +#if 0 + if (b) { + // CONNECT does not support indexing via ALTER TABLE + my_message(ER_UNKNOWN_ERROR, + "CONNECT does not support index modification via ALTER TABLE", + MYF(0)); + DBUG_RETURN(HA_ERR_UNSUPPORTED); + } // endif b +#endif // 0 + + } // endif Xchk + +#endif // 0 } // endif Xchk table= st; DBUG_RETURN(rc); } // end of create +/** + Used to check whether a file based outward table can be populated by + an ALTER TABLE command. The conditions are: + - file does not exist or is void + - user has file privilege +*/ +bool ha_connect::FileExists(const char *fn) +{ + if (!fn || !*fn) + return false; + + if (table) { + char *s, filename[_MAX_PATH], path[128]; + int n; + struct stat info; + + if (check_access(ha_thd(), FILE_ACL, table->s->db.str, + NULL, NULL, 0, 0)) + return true; + +#if defined(WIN32) + s= "\\"; +#else // !WIN32 + s= "/"; +#endif // !WIN32 + + strcat(strcat(strcat(strcpy(path, "."), s), table->s->db.str), s); + PlugSetPath(filename, fn, path); + n= stat(filename, &info); + + if (n < 0) { + if (errno != ENOENT) { + char buf[_MAX_PATH + 20]; + + sprintf(buf, "Error %d for file %s", errno, filename); + push_warning(table->in_use, Sql_condition::WARN_LEVEL_WARN, 0, buf); + return true; + } else + return false; + + } else + return (info.st_size) ? true : false; + + } // endif table + + return true; +} // end of FileExists + +/** + check whether a string option have changed + */ +bool ha_connect::SameChar(TABLE *tab, char *opn) +{ + char *str1, *str2; + bool b1, b2; + + tshp= tab->s; // The altered table + str1= GetStringOption(opn); + tshp= NULL; + str2= GetStringOption(opn); + b1= (!str1 || !*str1); + b2= (!str2 || !*str2); + + if (b1 && b2) + return true; + else if ((b1 && !b2) || (!b1 && b2) || stricmp(str1, str2)) + return false; + + return true; +} // end of SameChar + +/** + check whether a Boolean option have changed + */ +bool ha_connect::SameBool(TABLE *tab, char *opn) +{ + bool b1, b2; + + tshp= tab->s; // The altered table + b1= GetBooleanOption(opn, false); + tshp= NULL; + b2= GetBooleanOption(opn, false); + return (b1 == b2); +} // end of SameBool + +/** + check whether an integer option have changed + */ +bool ha_connect::SameInt(TABLE *tab, char *opn) +{ + int i1, i2; + + tshp= tab->s; // The altered table + i1= GetIntegerOption(opn); + tshp= NULL; + i2= GetIntegerOption(opn); + + if (!stricmp(opn, "lrecl")) + return (i1 == i2 || !i1 || !i2); + else if (!stricmp(opn, "ending")) + return (i1 == i2 || i1 <= 0 || i2 <= 0); + else + return (i1 == i2); + +} // end of SameInt + + + /** + Check if a storage engine supports a particular alter table in-place + + @param altered_table TABLE object for new version of table. + @param ha_alter_info Structure describing changes to be done + by ALTER TABLE and holding data used + during in-place alter. + + @retval HA_ALTER_ERROR Unexpected error. + @retval HA_ALTER_INPLACE_NOT_SUPPORTED Not supported, must use copy. + @retval HA_ALTER_INPLACE_EXCLUSIVE_LOCK Supported, but requires X lock. + @retval HA_ALTER_INPLACE_SHARED_LOCK_AFTER_PREPARE + Supported, but requires SNW lock + during main phase. Prepare phase + requires X lock. + @retval HA_ALTER_INPLACE_SHARED_LOCK Supported, but requires SNW lock. + @retval HA_ALTER_INPLACE_NO_LOCK_AFTER_PREPARE + Supported, concurrent reads/writes + allowed. However, prepare phase + requires X lock. + @retval HA_ALTER_INPLACE_NO_LOCK Supported, concurrent + reads/writes allowed. + + @note The default implementation uses the old in-place ALTER API + to determine if the storage engine supports in-place ALTER or not. + + @note Called without holding thr_lock.c lock. + */ +enum_alter_inplace_result +ha_connect::check_if_supported_inplace_alter(TABLE *altered_table, + Alter_inplace_info *ha_alter_info) +{ + DBUG_ENTER("check_if_supported_alter"); + + bool idx= false, outward= false; + THD *thd= ha_thd(); + int sqlcom= thd_sql_command(thd); + TABTYPE newtyp, type= TAB_UNDEF; + HA_CREATE_INFO *create_info= ha_alter_info->create_info; +//PTOS pos= GetTableOptionStruct(table); + PTOS newopt, oldopt; + xp= GetUser(thd, xp); + PGLOBAL g= xp->g; + + if (!g || !table) { + my_message(ER_UNKNOWN_ERROR, "Cannot check ALTER operations", MYF(0)); + DBUG_RETURN(HA_ALTER_ERROR); + } // endif Xchk + + newopt= altered_table->s->option_struct; + oldopt= table->s->option_struct; + + // If this is the start of a new query, cleanup the previous one + if (xp->CheckCleanup()) { + tdbp= NULL; + valid_info= false; + } // endif CheckCleanup + + g->Alchecked= 1; // Tested in create + g->Xchk= NULL; + type= GetRealType(oldopt); + newtyp= GetRealType(newopt); + + // No copy algorithm for outward tables + outward= (!IsFileType(type) || (oldopt->filename && *oldopt->filename)); + + // Index operations + Alter_inplace_info::HA_ALTER_FLAGS index_operations= + Alter_inplace_info::ADD_INDEX | + Alter_inplace_info::DROP_INDEX | + Alter_inplace_info::ADD_UNIQUE_INDEX | + Alter_inplace_info::DROP_UNIQUE_INDEX | + Alter_inplace_info::ADD_PK_INDEX | + Alter_inplace_info::DROP_PK_INDEX; + + Alter_inplace_info::HA_ALTER_FLAGS inplace_offline_operations= + Alter_inplace_info::ALTER_COLUMN_EQUAL_PACK_LENGTH | + Alter_inplace_info::ALTER_COLUMN_NAME | + Alter_inplace_info::ALTER_COLUMN_DEFAULT | + Alter_inplace_info::CHANGE_CREATE_OPTION | + Alter_inplace_info::ALTER_RENAME | index_operations; + + if (ha_alter_info->handler_flags & index_operations || + !SameChar(altered_table, "optname") || + !SameBool(altered_table, "sepindex")) { + if (!IsTypeIndexable(type)) { + sprintf(g->Message, "Table type %s is not indexable", oldopt->type); + my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0)); + DBUG_RETURN(HA_ALTER_ERROR); + } // endif Indexable + + g->Xchk= new(g) XCHK; + PCHK xcp= (PCHK)g->Xchk; + + xcp->oldpix= GetIndexInfo(table->s); + xcp->newpix= GetIndexInfo(altered_table->s); + xcp->oldsep= GetBooleanOption("sepindex", false); + xcp->oldsep= xcp->SetName(g, GetStringOption("optname")); + tshp= altered_table->s; + xcp->newsep= GetBooleanOption("sepindex", false); + xcp->newsep= xcp->SetName(g, GetStringOption("optname")); + tshp= NULL; + + if (xtrace && g->Xchk) + printf( + "oldsep=%d newsep=%d oldopn=%s newopn=%s oldpix=%p newpix=%p\n", + xcp->oldsep, xcp->newsep, + SVP(xcp->oldopn), SVP(xcp->newopn), + xcp->oldpix, xcp->newpix); + + if (sqlcom == SQLCOM_ALTER_TABLE) + idx= true; + else + DBUG_RETURN(HA_ALTER_INPLACE_EXCLUSIVE_LOCK); + + } // endif index operation + + if (!SameChar(altered_table, "filename")) { + if (!outward) { + // Conversion to outward table is only allowed for file based + // tables whose file does not exist. + tshp= altered_table->s; + char *fn= GetStringOption("filename"); + tshp= NULL; + + if (FileExists(fn)) { + strcpy(g->Message, "Operation denied. Table data would be lost."); + my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0)); + DBUG_RETURN(HA_ALTER_ERROR); + } else + goto fin; + + } else + goto fin; + + } // endif filename + + /* Is there at least one operation that requires copy algorithm? */ + if (ha_alter_info->handler_flags & ~inplace_offline_operations) + goto fin; + + /* + ALTER TABLE tbl_name CONVERT TO CHARACTER SET .. and + ALTER TABLE table_name DEFAULT CHARSET = .. most likely + change column charsets and so not supported in-place through + old API. + + Changing of PACK_KEYS, MAX_ROWS and ROW_FORMAT options were + not supported as in-place operations in old API either. + */ + if (create_info->used_fields & (HA_CREATE_USED_CHARSET | + HA_CREATE_USED_DEFAULT_CHARSET | + HA_CREATE_USED_PACK_KEYS | + HA_CREATE_USED_MAX_ROWS) || + (table->s->row_type != create_info->row_type)) + goto fin; + +#if 0 + uint table_changes= (ha_alter_info->handler_flags & + Alter_inplace_info::ALTER_COLUMN_EQUAL_PACK_LENGTH) ? + IS_EQUAL_PACK_LENGTH : IS_EQUAL_YES; + + if (table->file->check_if_incompatible_data(create_info, table_changes) + == COMPATIBLE_DATA_YES) + DBUG_RETURN(HA_ALTER_INPLACE_EXCLUSIVE_LOCK); +#endif // 0 + + // This was in check_if_incompatible_data + if (type == newtyp && + SameInt(altered_table, "lrecl") && + SameInt(altered_table, "elements") && + SameInt(altered_table, "header") && + SameInt(altered_table, "quoted") && + SameInt(altered_table, "ending") && + SameInt(altered_table, "compressed")) + DBUG_RETURN(HA_ALTER_INPLACE_EXCLUSIVE_LOCK); + +fin: + if (idx) { + // Indexing is only supported inplace + my_message(ER_UNKNOWN_ERROR, + "Alter operations not supported together by CONNECT", MYF(0)); + DBUG_RETURN(HA_ALTER_ERROR); + } else if (outward) { + push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, + "This is an outward table, table data were not modified."); + DBUG_RETURN(HA_ALTER_INPLACE_EXCLUSIVE_LOCK); + } else + DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED); + +} // end of check_if_supported_inplace_alter + /** check_if_incompatible_data() called if ALTER TABLE can't detect otherwise @@ -4818,46 +5343,17 @@ int ha_connect::create(const char *name, TABLE *table_arg, (sql/sql_tables.cc) to decide should we rewrite whole table or only .frm file. + @note: This function is no more called by check_if_supported_inplace_alter */ bool ha_connect::check_if_incompatible_data(HA_CREATE_INFO *info, uint table_changes) { -//ha_table_option_struct *param_old, *param_new; DBUG_ENTER("ha_connect::check_if_incompatible_data"); // TO DO: really implement and check it. - THD *thd= current_thd; - - push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, - "The current version of CONNECT did not check what you changed in ALTER. Use at your own risk"); - - if (table) { - PTOS newopt= info->option_struct; - PTOS oldopt= table->s->option_struct; - -#if 0 - if (newopt->sepindex != oldopt->sepindex) { - // All indexes to be remade - PGLOBAL g= GetPlug(thd); - - if (!g) - push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, - "Execute OPTIMIZE TABLE to remake the indexes"); - else - g->Xchk= new(g) XCHK; - - } // endif sepindex -#endif // 0 - - if (oldopt->type != newopt->type) - DBUG_RETURN(COMPATIBLE_DATA_NO); - - if (newopt->filename) - DBUG_RETURN(COMPATIBLE_DATA_NO); - - } // endif table - - DBUG_RETURN(COMPATIBLE_DATA_YES); + push_warning(ha_thd(), Sql_condition::WARN_LEVEL_WARN, 0, + "Unexpected call to check_if_incompatible_data."); + DBUG_RETURN(COMPATIBLE_DATA_NO); } // end of check_if_incompatible_data diff --git a/storage/connect/ha_connect.h b/storage/connect/ha_connect.h index 754e2e37a7f..908c26fefdc 100644 --- a/storage/connect/ha_connect.h +++ b/storage/connect/ha_connect.h @@ -50,9 +50,20 @@ typedef struct _xinfo { class XCHK : public BLOCK { public: - XCHK(void) {oldsep= newsep= false; oldpix= newpix= NULL;} + XCHK(void) {oldsep= newsep= false; + oldopn= newopn= NULL; + oldpix= newpix= NULL;} + + inline char *SetName(PGLOBAL g, char *name) { + char *nm= NULL; + if (name) {nm= (char*)PlugSubAlloc(g, NULL, strlen(name) + 1); + strcpy(nm, name);} + return nm;} + bool oldsep; // Sepindex before create/alter bool newsep; // Sepindex after create/alter + char *oldopn; // Optname before create/alter + char *newopn; // Optname after create/alter PIXDEF oldpix; // The indexes before create/alter PIXDEF newpix; // The indexes after create/alter }; // end of class XCHK @@ -156,15 +167,20 @@ class ha_connect: public handler // CONNECT Implementation static bool connect_init(void); static bool connect_end(void); + TABTYPE GetRealType(PTOS pos); char *GetStringOption(char *opname, char *sdef= NULL); PTOS GetTableOptionStruct(TABLE *table_arg); bool GetBooleanOption(char *opname, bool bdef); bool SetBooleanOption(char *opname, bool b); int GetIntegerOption(char *opname); bool SetIntegerOption(char *opname, int n); + bool SameChar(TABLE *tab, char *opn); + bool SameInt(TABLE *tab, char *opn); + bool SameBool(TABLE *tab, char *opn); + bool FileExists(const char *fn); PFOS GetFieldOptionStruct(Field *fp); void *GetColumnOption(PGLOBAL g, void *field, PCOLINFO pcf); - PIXDEF GetIndexInfo(void); + PIXDEF GetIndexInfo(TABLE_SHARE *s= NULL); const char *GetDBName(const char *name); const char *GetTableName(void); //int GetColNameLen(Field *fp); @@ -199,18 +215,19 @@ class ha_connect: public handler */ const char **bas_ext() const; + /** + Check if a storage engine supports a particular alter table in-place + @note Called without holding thr_lock.c lock. + */ + virtual enum_alter_inplace_result + check_if_supported_inplace_alter(TABLE *altered_table, + Alter_inplace_info *ha_alter_info); + /** @brief This is a list of flags that indicate what functionality the storage engine implements. The current table flags are documented in handler.h */ - ulonglong table_flags() const - { - 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_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE | - /*HA_NULL_IN_KEY |*/ HA_MUST_USE_TABLE_CONDITION_PUSHDOWN); - } + ulonglong table_flags() const; /** @brief This is a bitmap of flags that indicates how the storage engine @@ -464,6 +481,7 @@ const char *GetValStr(OPVAL vop, bool neg); XINFO xinfo; // The table info structure bool valid_info; // True if xinfo is valid bool stop; // Used when creating index + bool alter; // True when converting to other engine int indexing; // Type of indexing for CONNECT int locked; // Table lock THR_LOCK_DATA lock_data; diff --git a/storage/connect/mycat.cc b/storage/connect/mycat.cc index 092d38a142a..dc5db156af0 100644 --- a/storage/connect/mycat.cc +++ b/storage/connect/mycat.cc @@ -259,6 +259,89 @@ uint GetFuncID(const char *func) return fnc; } // end of GetFuncID +/***********************************************************************/ +/* OEMColumn: Get table column info for an OEM table. */ +/***********************************************************************/ +PQRYRES OEMColumns(PGLOBAL g, PTOS topt, char *tab, char *db, bool info) + { + typedef PQRYRES (__stdcall *XCOLDEF) (PGLOBAL, PVOID, char*, char*, bool); + const char *module, *subtype; + char c, getname[40] = "Col"; +#if defined(WIN32) + HANDLE hdll; /* Handle to the external DLL */ +#else // !WIN32 + void *hdll; /* Handle for the loaded shared library */ +#endif // !WIN32 + XCOLDEF coldef = NULL; + PQRYRES qrp = NULL; + + module = topt->module; + subtype = topt->subtype; + + if (!module || !subtype) + return NULL; + + // The exported name is always in uppercase + for (int i = 0; ; i++) { + c = subtype[i]; + getname[i + 3] = toupper(c); + if (!c) break; + } // endfor i + +#if defined(WIN32) + // Load the Dll implementing the table + if (!(hdll = LoadLibrary(module))) { + char buf[256]; + DWORD rc = GetLastError(); + + sprintf(g->Message, MSG(DLL_LOAD_ERROR), rc, module); + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0, + (LPTSTR)buf, sizeof(buf), NULL); + strcat(strcat(g->Message, ": "), buf); + return NULL; + } // endif hDll + + // Get the function returning an instance of the external DEF class + if (!(coldef = (XCOLDEF)GetProcAddress((HINSTANCE)hdll, getname))) { + sprintf(g->Message, MSG(PROCADD_ERROR), GetLastError(), getname); + FreeLibrary((HMODULE)hdll); + return NULL; + } // endif coldef +#else // !WIN32 + const char *error = NULL; + + // Load the desired shared library + if (!(hdll = dlopen(Module, RTLD_LAZY))) { + error = dlerror(); + sprintf(g->Message, MSG(SHARED_LIB_ERR), Module, SVP(error)); + return NULL; + } // endif Hdll + + // Get the function returning an instance of the external DEF class + if (!(coldef = (XCOLDEF)dlsym(hdll, getname))) { + error = dlerror(); + sprintf(g->Message, MSG(GET_FUNC_ERR), getname, SVP(error)); + dlclose(hdll); + return NULL; + } // endif coldef +#endif // !WIN32 + + // Just in case the external Get function does not set error messages + sprintf(g->Message, "Error getting column info from %s", subtype); + + // Get the table column definition + qrp = coldef(g, topt, tab, db, info); + +#if defined(WIN32) + FreeLibrary((HMODULE)hdll); +#else // !WIN32 + dlclose(hdll); +#endif // !WIN32 + + return qrp; + } // end of OEMColumns + /* ------------------------- Class CATALOG --------------------------- */ /***********************************************************************/ diff --git a/storage/connect/mysql-test/connect/r/bin.result b/storage/connect/mysql-test/connect/r/bin.result index 10deb54cb2e..bbf5614b555 100644 --- a/storage/connect/mysql-test/connect/r/bin.result +++ b/storage/connect/mysql-test/connect/r/bin.result @@ -50,8 +50,6 @@ dept INT(4) NOT NULL FIELD_FORMAT='S' INSERT INTO t1 VALUES (7777,'BILL','1973-06-30',4444,5555.555,777); ERROR HY000: Table 't1' is read only ALTER TABLE t1 READONLY=NO; -Warnings: -Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( @@ -71,8 +69,6 @@ fig name birth id salary dept 5555 RONALD 1980-02-26 3333 4444.44 555 7777 BILL 1973-06-30 4444 5555.56 777 ALTER TABLE t1 READONLY=YES; -Warnings: -Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( diff --git a/storage/connect/mysql-test/connect/r/csv.result b/storage/connect/mysql-test/connect/r/csv.result index 94fd95a5d83..3f424964881 100644 --- a/storage/connect/mysql-test/connect/r/csv.result +++ b/storage/connect/mysql-test/connect/r/csv.result @@ -63,8 +63,6 @@ Archibald 2001-05-17 3 Nabucho 2003-08-12 2 RONALD 1980-02-26 4 ALTER TABLE t1 READONLY=no; -Warnings: -Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( @@ -80,8 +78,6 @@ Nabucho 2003-08-12 2 RONALD 1980-02-26 4 BILL 1973-06-30 5 ALTER TABLE t1 READONLY=1; -Warnings: -Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( diff --git a/storage/connect/mysql-test/connect/r/dbf.result b/storage/connect/mysql-test/connect/r/dbf.result index c7bb5739e75..bc09f85a631 100644 --- a/storage/connect/mysql-test/connect/r/dbf.result +++ b/storage/connect/mysql-test/connect/r/dbf.result @@ -69,8 +69,6 @@ a 10 20 ALTER TABLE t1 READONLY=Yes; -Warnings: -Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( @@ -85,8 +83,6 @@ ERROR HY000: Table 't1' is read only TRUNCATE TABLE t1; ERROR HY000: Table 't1' is read only ALTER TABLE t1 READONLY=NO; -Warnings: -Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( @@ -508,12 +504,12 @@ DROP TABLE IF EXISTS t1; CREATE TABLE t1 ( a VARCHAR(10) NOT NULL -) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf'; +) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1c.dbf'; INSERT INTO t1 VALUES ('10'); SELECT * FROM t1; a 10 -CALL dbf_header('MYSQLD_DATADIR/test/t1.dbf'); +CALL dbf_header('MYSQLD_DATADIR/test/t1c.dbf'); -------- -------- FileSize 77 DBF_Version 03 @@ -532,17 +528,15 @@ Dec 0 Flags 00 -------- -------- ALTER TABLE t1 MODIFY a VARCHAR(10) NOT NULL; -Warnings: -Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `a` varchar(10) NOT NULL -) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=DBF `FILE_NAME`='t1.dbf' +) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=DBF `FILE_NAME`='t1c.dbf' SELECT * FROM t1; a 10 -CALL dbf_header('MYSQLD_DATADIR/test/t1.dbf'); +CALL dbf_header('MYSQLD_DATADIR/test/t1c.dbf'); -------- -------- FileSize 77 DBF_Version 03 @@ -561,15 +555,17 @@ Dec 0 Flags 00 -------- -------- ALTER TABLE t1 MODIFY a INT(10) NOT NULL; +Warnings: +Warning 1105 This is an outward table, table data were not modified. SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `a` int(10) NOT NULL -) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=DBF `FILE_NAME`='t1.dbf' +) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=DBF `FILE_NAME`='t1c.dbf' SELECT * FROM t1; a 10 -CALL dbf_header('MYSQLD_DATADIR/test/t1.dbf'); +CALL dbf_header('MYSQLD_DATADIR/test/t1c.dbf'); -------- -------- FileSize 77 DBF_Version 03 diff --git a/storage/connect/mysql-test/connect/r/dir.result b/storage/connect/mysql-test/connect/r/dir.result index f4feb5fa960..34a591fb26c 100644 --- a/storage/connect/mysql-test/connect/r/dir.result +++ b/storage/connect/mysql-test/connect/r/dir.result @@ -13,8 +13,6 @@ boys .txt 282 boys2 .txt 282 boyswin .txt 288 ALTER TABLE t1 OPTION_LIST='subdir=0'; -Warnings: -Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( diff --git a/storage/connect/mysql-test/connect/r/fix.result b/storage/connect/mysql-test/connect/r/fix.result index c218561c3aa..96ba3f84a0d 100644 --- a/storage/connect/mysql-test/connect/r/fix.result +++ b/storage/connect/mysql-test/connect/r/fix.result @@ -22,8 +22,6 @@ SELECT * FROM t1; id 10 ALTER TABLE t1 READONLY=1; -Warnings: -Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( @@ -38,8 +36,6 @@ ERROR HY000: Table 't1' is read only TRUNCATE TABLE t1; ERROR HY000: Table 't1' is read only ALTER TABLE t1 READONLY=0; -Warnings: -Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( diff --git a/storage/connect/mysql-test/connect/r/index.result b/storage/connect/mysql-test/connect/r/index.result index b365046a55d..bffaaecc785 100644 --- a/storage/connect/mysql-test/connect/r/index.result +++ b/storage/connect/mysql-test/connect/r/index.result @@ -37,8 +37,6 @@ SUM(brut) # Testing file mapping # ALTER TABLE t1 MAPPED=yes; -Warnings: -Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk SELECT * FROM t1 LIMIT 10; matricule nom prenom sexe aanais mmnais ddentree ddnom brut net service sitmat formation 5745 ESCOURCHE BENEDICTE 2 1935 7 1962-12-01 1994-05-01 18345 14275.50 0 M TECHN diff --git a/storage/connect/mysql-test/connect/r/ini.result b/storage/connect/mysql-test/connect/r/ini.result index fa03435323e..79996eb8525 100644 --- a/storage/connect/mysql-test/connect/r/ini.result +++ b/storage/connect/mysql-test/connect/r/ini.result @@ -185,8 +185,6 @@ UK 10 FR 20 RU 30 ALTER TABLE t1 READONLY=1; -Warnings: -Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( @@ -202,8 +200,6 @@ ERROR HY000: Table 't1' is read only TRUNCATE TABLE t1; ERROR HY000: Table 't1' is read only ALTER TABLE t1 READONLY=0; -Warnings: -Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( diff --git a/storage/connect/mysql-test/connect/r/occur.result b/storage/connect/mysql-test/connect/r/occur.result index a497dfc9942..fbcda4660be 100644 --- a/storage/connect/mysql-test/connect/r/occur.result +++ b/storage/connect/mysql-test/connect/r/occur.result @@ -193,6 +193,8 @@ Kevin 8 Lisbeth 2 Mary 2 ALTER TABLE xpet MODIFY number INT NOT NULL; +Warnings: +Warning 1105 This is an outward table, table data were not modified. SELECT * FROM xpet; name race number John dog 2 diff --git a/storage/connect/mysql-test/connect/r/pivot.result b/storage/connect/mysql-test/connect/r/pivot.result index 11eee6233a4..2e4a924c8c3 100644 --- a/storage/connect/mysql-test/connect/r/pivot.result +++ b/storage/connect/mysql-test/connect/r/pivot.result @@ -44,8 +44,6 @@ Car DOUBLE(8,2) FLAG=1, Food DOUBLE(8,2) FLAG=1) ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=expenses; ALTER TABLE pivex OPTION_LIST='port=PORT'; -Warnings: -Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk SELECT * FROM pivex; Who Week Beer Car Food Beth 3 16.00 0.00 0.00 @@ -61,6 +59,8 @@ Joe 5 14.00 0.00 12.00 # Restricting the columns in a Pivot Table # ALTER TABLE pivex DROP COLUMN week; +Warnings: +Warning 1105 This is an outward table, table data were not modified. SELECT * FROM pivex; Who Beer Car Food Beth 51.00 0.00 29.00 @@ -81,8 +81,6 @@ SRCDEF='select who, week, what, sum(amount) as amount from expenses where week i 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 SELECT * FROM pivex; Who Week Beer Car Food Beth 4 15.00 0.00 17.00 @@ -103,8 +101,6 @@ What CHAR(12) NOT NULL, `5` DOUBLE(8,2) FLAG=1) ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=expenses; ALTER TABLE pivex OPTION_LIST='PivotCol=Week,port=PORT'; -Warnings: -Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk SELECT * FROM pivex; Who What 3 4 5 Beth Beer 16.00 15.00 20.00 @@ -130,8 +126,6 @@ SRCDEF='select who, what, case when week=3 then ''First'' when week=5 then ''Las 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 SELECT * FROM pivex; Who What First Middle Last Beth Beer 104.96 98.40 131.20 @@ -202,8 +196,6 @@ ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=pets OPTION_LIST='PivotCol=race,groupby= SELECT * FROM pivet; ERROR HY000: Got error 122 'Cannot find matching column' from CONNECT ALTER TABLE pivet OPTION_LIST='PivotCol=race,groupby=1,accept=1'; -Warnings: -Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk SELECT * FROM pivet; name dog cat John 2 0 diff --git a/storage/connect/mysql-test/connect/r/vec.result b/storage/connect/mysql-test/connect/r/vec.result index 926c0f2f4c6..e93305fb07a 100644 --- a/storage/connect/mysql-test/connect/r/vec.result +++ b/storage/connect/mysql-test/connect/r/vec.result @@ -94,8 +94,6 @@ t1vec .blk 8 # Testing READONLY # ALTER TABLE t1 READONLY=yes; -Warnings: -Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( @@ -111,8 +109,6 @@ ERROR HY000: Table 't1' is read only TRUNCATE TABLE t1; ERROR HY000: Table 't1' is read only ALTER TABLE t1 READONLY=no; -Warnings: -Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( diff --git a/storage/connect/mysql-test/connect/r/xml.result b/storage/connect/mysql-test/connect/r/xml.result index e412e44a9ba..aeb1f5edbcd 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) <?xml version="1.0" encoding="iso-8859-1"?> -<!-- Created by CONNECT Version 1.01.0011 December 15, 2013 --> +<!-- Created by CONNECT Version 1.02.0001 February 03, 2014 --> <t1> <line> <node>ÀÃÂÃ</node> diff --git a/storage/connect/mysql-test/connect/t/dbf.test b/storage/connect/mysql-test/connect/t/dbf.test index 3fd30f98f20..7b364e9b921 100644 --- a/storage/connect/mysql-test/connect/t/dbf.test +++ b/storage/connect/mysql-test/connect/t/dbf.test @@ -442,30 +442,32 @@ DROP TABLE IF EXISTS t1; --echo # --echo # Testing ALTER --echo # +# Temporarily change the file name because ALTER that are not executed not in place +# delete the data file when it has the same path/name than the default file name. CREATE TABLE t1 ( a VARCHAR(10) NOT NULL -) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf'; +) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1c.dbf'; INSERT INTO t1 VALUES ('10'); SELECT * FROM t1; ---chmod 0777 $MYSQLD_DATADIR/test/t1.dbf +--chmod 0777 $MYSQLD_DATADIR/test/t1c.dbf --vertical_results --replace_result $MYSQLD_DATADIR MYSQLD_DATADIR -eval CALL dbf_header('$MYSQLD_DATADIR/test/t1.dbf'); +eval CALL dbf_header('$MYSQLD_DATADIR/test/t1c.dbf'); --horizontal_results ALTER TABLE t1 MODIFY a VARCHAR(10) NOT NULL; SHOW CREATE TABLE t1; SELECT * FROM t1; --vertical_results --replace_result $MYSQLD_DATADIR MYSQLD_DATADIR -eval CALL dbf_header('$MYSQLD_DATADIR/test/t1.dbf'); +eval CALL dbf_header('$MYSQLD_DATADIR/test/t1c.dbf'); --horizontal_results ALTER TABLE t1 MODIFY a INT(10) NOT NULL; SHOW CREATE TABLE t1; SELECT * FROM t1; --vertical_results --replace_result $MYSQLD_DATADIR MYSQLD_DATADIR -eval CALL dbf_header('$MYSQLD_DATADIR/test/t1.dbf'); +eval CALL dbf_header('$MYSQLD_DATADIR/test/t1c.dbf'); --horizontal_results # TODO: this does not work on Windows @@ -478,7 +480,7 @@ eval CALL dbf_header('$MYSQLD_DATADIR/test/t1.dbf'); #eval CALL dbf_header('$MYSQLD_DATADIR/test/t1.dbf'); #--horizontal_results DROP TABLE IF EXISTS t1; ---remove_file $MYSQLD_DATADIR/test/t1.dbf +--remove_file $MYSQLD_DATADIR/test/t1c.dbf --echo # diff --git a/storage/connect/plgcnx.h b/storage/connect/plgcnx.h index 7ce72b45268..fe3997d1986 100644 --- a/storage/connect/plgcnx.h +++ b/storage/connect/plgcnx.h @@ -1,6 +1,6 @@ /**************************************************************************/ /* PLGCNX.H */ -/* Copyright to the author: Olivier Bertrand 2000-2012 */ +/* Copyright to the author: Olivier Bertrand 2000-2014 */ /* */ /* This is the connection DLL's declares. */ /**************************************************************************/ @@ -62,6 +62,7 @@ enum INFO {INDX_RC, /* Index of PlugDB return code field */ INDX_SIZE, /* Index of returned data size field */ INDX_MAX}; /* Size of info array */ +#ifdef NOT_USED /**************************************************************************/ /* Internal message types. */ /**************************************************************************/ @@ -97,9 +98,9 @@ enum VENDOR {VDR_UNKNOWN = -2, /* Not known or not connected */ /**************************************************************************/ enum CKEYS {K_ProgMsg, K_Lang, K_ActiveDB, K_Cmax}; enum LKEYS {K_NBcol, K_NBlin, K_CurPos, K_RC, K_Result, K_Elapsed, - K_Continued, K_Maxsize, K_Lmax, K_Maxcol, + K_Continued, K_Maxsize, K_Affrows, K_Lmax, K_Maxcol, K_Maxres, K_Maxlin, K_NBparm}; -enum NKEYS {K_Type, K_Length, K_Prec, K_DataLen, K_Nmax}; +enum NKEYS {K_Type, K_Length, K_Prec, K_DataLen, K_Unsigned, K_Nmax}; /**************************************************************************/ /* Result description structures. */ @@ -157,7 +158,6 @@ typedef struct _ResDesc { #define XTRN #endif -#ifdef NOT_USED //#if !defined(NO_FUNC) #ifdef __cplusplus extern "C" { @@ -172,7 +172,7 @@ XTRN bool CNXFUNC(PLGGetCharValue)(CNXKEY, char *, int, int); XTRN bool CNXFUNC(PLGGetIntValue)(CNXKEY, int *, int); XTRN bool CNXFUNC(PLGGetColValue) (CNXKEY, int *, int, int); XTRN bool CNXFUNC(PLGGetMessage) (CNXKEY, char *, int); -XTRN bool CNXFUNC(PLGGetHeader) (CNXKEY, char *, int, int); +XTRN bool CNXFUNC(PLGGetHeader) (CNXKEY, char *, int, int, int); #ifdef __cplusplus } diff --git a/storage/connect/plgdbsem.h b/storage/connect/plgdbsem.h index b62979451ee..e251ded13df 100644 --- a/storage/connect/plgdbsem.h +++ b/storage/connect/plgdbsem.h @@ -1,7 +1,7 @@ /************** PlgDBSem H Declares Source Code File (.H) **************/ -/* Name: PLGDBSEM.H Version 3.5 */ +/* Name: PLGDBSEM.H Version 3.6 */ /* */ -/* (C) Copyright to the author Olivier BERTRAND 1998-2012 */ +/* (C) Copyright to the author Olivier BERTRAND 1998-2014 */ /* */ /* This file contains the PlugDB++ application type definitions. */ /***********************************************************************/ @@ -166,7 +166,8 @@ enum MODE {MODE_ERROR = -1, /* Invalid mode */ MODE_WRITE = 20, /* Input/Output mode */ MODE_UPDATE = 30, /* Input/Output mode */ MODE_INSERT = 40, /* Input/Output mode */ - MODE_DELETE = 50}; /* Input/Output mode */ + MODE_DELETE = 50, /* Input/Output mode */ + MODE_ALTER = 60}; /* alter mode */ #if !defined(RC_OK_DEFINED) #define RC_OK_DEFINED @@ -549,8 +550,6 @@ PPARM Vcolist(PGLOBAL, PTDB, PSZ, bool); void PlugPutOut(PGLOBAL, FILE *, short, void *, uint); void PlugLineDB(PGLOBAL, PSZ, short, void *, uint); char *PlgGetDataPath(PGLOBAL g); -void *PlgDBalloc(PGLOBAL, void *, MBLOCK&); -void *PlgDBrealloc(PGLOBAL, void *, MBLOCK&, size_t); void AddPointer(PTABS, void *); PDTP MakeDateFormat(PGLOBAL, PSZ, bool, bool, int); int ExtractDate(char *, PDTP, int, int val[6]); @@ -558,9 +557,10 @@ int ExtractDate(char *, PDTP, int, int val[6]); /**************************************************************************/ /* Allocate the result structure that will contain result data. */ /**************************************************************************/ -PQRYRES PlgAllocResult(PGLOBAL g, int ncol, int maxres, int ids, - int *buftyp, XFLD *fldtyp, - unsigned int *length, bool blank, bool nonull); +DllExport PQRYRES PlgAllocResult(PGLOBAL g, int ncol, int maxres, int ids, + int *buftyp, XFLD *fldtyp, + unsigned int *length, + bool blank, bool nonull); /***********************************************************************/ /* Exported utility routines. */ @@ -576,12 +576,16 @@ DllExport PCATLG PlgGetCatalog(PGLOBAL g, bool jump = true); DllExport bool PlgSetXdbPath(PGLOBAL g, PSZ, PSZ, char *, int, char *, int); DllExport void PlgDBfree(MBLOCK&); DllExport void *PlgDBSubAlloc(PGLOBAL g, void *memp, size_t size); +DllExport void *PlgDBalloc(PGLOBAL, void *, MBLOCK&); +DllExport void *PlgDBrealloc(PGLOBAL, void *, MBLOCK&, size_t); //lExport PSZ GetIniString(PGLOBAL, void *, LPCSTR, LPCSTR, LPCSTR, LPCSTR); //lExport int GetIniSize(char *, char *, char *, char *); //lExport bool WritePrivateProfileInt(LPCSTR, LPCSTR, int, LPCSTR); DllExport void NewPointer(PTABS, void *, void *); DllExport char *GetIni(int n= 0); DllExport void SetTrc(void); +DllExport char *GetListOption(PGLOBAL, const char *, const char *, + const char *def=NULL); #define MSGID_NONE 0 #define MSGID_CANNOT_OPEN 1 @@ -597,4 +601,4 @@ int global_open(GLOBAL *g, int msgid, const char *filename, int flags, int mode) DllExport LPCSTR PlugSetPath(LPSTR to, LPCSTR name, LPCSTR dir); char *MakeEscape(PGLOBAL g, char* str, char q); -bool PushWarning(PGLOBAL, PTDBASE, int level = 1); +DllExport bool PushWarning(PGLOBAL, PTDBASE, int level = 1); diff --git a/storage/connect/plgdbutl.cpp b/storage/connect/plgdbutl.cpp index b5c4239c992..c3c74463271 100644 --- a/storage/connect/plgdbutl.cpp +++ b/storage/connect/plgdbutl.cpp @@ -1,11 +1,11 @@ /********** PlgDBUtl Fpe C++ Program Source Code File (.CPP) ***********/ /* PROGRAM NAME: PLGDBUTL */ /* ------------- */ -/* Version 3.8 */ +/* Version 3.9 */ /* */ /* COPYRIGHT: */ /* ---------- */ -/* (C) Copyright to the author Olivier BERTRAND 1998-2013 */ +/* (C) Copyright to the author Olivier BERTRAND 1998-2014 */ /* */ /* WHAT THIS PROGRAM DOES: */ /* ----------------------- */ @@ -90,6 +90,7 @@ bool Initdone = false; bool plugin = false; // True when called by the XDB plugin handler extern "C" { +extern char connectini[]; char plgxini[_MAX_PATH] = PLGXINI; char plgini[_MAX_PATH] = PLGINI; #if defined(WIN32) @@ -232,6 +233,7 @@ DllExport char *GetIni(int n) #if defined(XMSG) case 5: return msglang; break; #endif // XMSG + case 6: return connectini; break; // default: return plgini; } // endswitch GetIni @@ -1329,7 +1331,7 @@ void *PlgDBalloc(PGLOBAL g, void *area, MBLOCK& mp) maxsub = (pph->FreeBlk < minsub) ? 0 : pph->FreeBlk - minsub; mp.Sub = mp.Size <= ((mp.Sub) ? maxsub : (maxsub >> 2)); - if (trace) + if (trace > 1) htrc("PlgDBalloc: in %p size=%d used=%d free=%d sub=%d\n", arp, mp.Size, pph->To_Free, pph->FreeBlk, mp.Sub); @@ -1372,7 +1374,7 @@ void *PlgDBrealloc(PGLOBAL g, void *area, MBLOCK& mp, size_t newsize) // assert (mp.Memp != NULL); #endif - if (trace) + if (trace > 1) htrc("PlgDBrealloc: %p size=%d sub=%d\n", mp.Memp, mp.Size, mp.Sub); if (newsize == mp.Size) @@ -1429,7 +1431,7 @@ void *PlgDBrealloc(PGLOBAL g, void *area, MBLOCK& mp, size_t newsize) /***********************************************************************/ void PlgDBfree(MBLOCK& mp) { - if (trace) + if (trace > 1) htrc("PlgDBfree: %p sub=%d size=%d\n", mp.Memp, mp.Sub, mp.Size); if (!mp.Sub && mp.Memp) diff --git a/storage/connect/plugutil.c b/storage/connect/plugutil.c index ec2ac399ad0..91b850022fb 100644 --- a/storage/connect/plugutil.c +++ b/storage/connect/plugutil.c @@ -152,6 +152,7 @@ PGLOBAL PlugInit(LPCSTR Language, uint worksize) g->Sarea_Size = worksize; g->Trace = 0; g->Createas = 0; + g->Alchecked = 0; g->Activityp = g->ActivityStart = NULL; g->Xchk = NULL; strcpy(g->Message, ""); diff --git a/storage/connect/tabfix.cpp b/storage/connect/tabfix.cpp index 2358dc07638..99063e86b57 100644 --- a/storage/connect/tabfix.cpp +++ b/storage/connect/tabfix.cpp @@ -331,7 +331,7 @@ void BINCOL::ReadColumn(PGLOBAL g) int rc; PTDBFIX tdbp = (PTDBFIX)To_Tdb; - if (trace) + if (trace > 1) htrc("BIN ReadColumn: col %s R%d coluse=%.4X status=%.4X buf_type=%d\n", Name, tdbp->GetTdb_No(), ColUse, Status, Buf_Type); diff --git a/storage/connect/table.cpp b/storage/connect/table.cpp index efe203e8e75..37035ed752d 100644 --- a/storage/connect/table.cpp +++ b/storage/connect/table.cpp @@ -1,7 +1,7 @@ /************** Table C++ Functions Source Code File (.CPP) ************/ -/* Name: TABLE.CPP Version 2.6 */ +/* Name: TABLE.CPP Version 2.7 */ /* */ -/* (C) Copyright to the author Olivier BERTRAND 1999-2013 */ +/* (C) Copyright to the author Olivier BERTRAND 1999-2014 */ /* */ /* This file contains the TBX, TDB and OPJOIN classes functions. */ /***********************************************************************/ @@ -262,6 +262,17 @@ PCATLG TDBASE::GetCat(void) return (To_Def) ? To_Def->GetCat() : NULL; } // end of GetCat +/***********************************************************************/ +/* Return the pointer on the charset of this table. */ +/***********************************************************************/ +CHARSET_INFO *TDBASE::data_charset(void) + { + // If no DATA_CHARSET is specified, we assume that character + // set of the remote data is the same with CHARACTER SET + // definition of the SQL column. + return m_data_charset ? m_data_charset : &my_charset_bin; + } // end of data_charset + /***********************************************************************/ /* Return the datapath of the DB this table belongs to. */ /***********************************************************************/ diff --git a/storage/connect/tabmysql.cpp b/storage/connect/tabmysql.cpp index fcf083bcbce..564eddbaf2b 100644 --- a/storage/connect/tabmysql.cpp +++ b/storage/connect/tabmysql.cpp @@ -1283,7 +1283,7 @@ void MYSQLCOL::ReadColumn(PGLOBAL g) tdbp->Fetched = TRUE; if ((buf = ((PTDBMY)To_Tdb)->Myc.GetCharField(Rank))) { - if (trace) + if (trace > 1) htrc("MySQL ReadColumn: name=%s buf=%s\n", Name, buf); // TODO: have a true way to differenciate temporal values diff --git a/storage/connect/tabxml.cpp b/storage/connect/tabxml.cpp index 5fef4fd9ef0..aa1133b0e92 100644 --- a/storage/connect/tabxml.cpp +++ b/storage/connect/tabxml.cpp @@ -1,9 +1,9 @@ /************* Tabxml C++ Program Source Code File (.CPP) **************/ /* PROGRAM NAME: TABXML */ /* ------------- */ -/* Version 2.6 */ +/* Version 2.7 */ /* */ -/* Author Olivier BERTRAND 2007 - 2013 */ +/* Author Olivier BERTRAND 2007 - 2014 */ /* */ /* This program are the XML tables classes using MS-DOM or libxml2. */ /***********************************************************************/ @@ -47,6 +47,7 @@ #include "xindex.h" #include "plgxml.h" #include "tabxml.h" +#include "tabmul.h" extern "C" { extern char version[]; @@ -136,7 +137,8 @@ bool XMLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) } // endswitch typname Tabname = Cat->GetStringCatInfo(g, "Name", Name); // Deprecated - Tabname = Cat->GetStringCatInfo(g, "Table_name", Tabname); + Tabname = Cat->GetStringCatInfo(g, "Table_name", Tabname); // Deprecated + Tabname = Cat->GetStringCatInfo(g, "Tabname", Tabname); Rowname = Cat->GetStringCatInfo(g, "Rownode", defrow); Colname = Cat->GetStringCatInfo(g, "Colnode", defcol); Mulnode = Cat->GetStringCatInfo(g, "Mulnode", ""); @@ -177,7 +179,12 @@ bool XMLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) /***********************************************************************/ PTDB XMLDEF::GetTable(PGLOBAL g, MODE m) { - return new(g) TDBXML(this); + PTDBASE tdbp = new(g) TDBXML(this); + + if (Multiple) + tdbp = new(g) TDBMUL(tdbp); + + return tdbp; } // end of GetTable /***********************************************************************/ @@ -245,6 +252,7 @@ TDBXML::TDBXML(PXMLDEF tdp) : TDBASE(tdp) Void = false; Usedom = tdp->Usedom; Header = tdp->Header; + Multiple = tdp->Multiple; Nrow = -1; Irow = Header - 1; Nsub = 0; @@ -287,6 +295,7 @@ TDBXML::TDBXML(PTDBXML tdbp) : TDBASE(tdbp) Void = tdbp->Void; Usedom = tdbp->Usedom; Header = tdbp->Header; + Multiple = tdbp->Multiple; Nrow = tdbp->Nrow; Irow = tdbp->Irow; Nsub = tdbp->Nsub; @@ -578,7 +587,7 @@ bool TDBXML::Initialize(PGLOBAL g) #endif } // end of try-catches - if (Root && Columns && !Nodedone) { + if (Root && Columns && (Multiple || !Nodedone)) { // Allocate class nodes to avoid dynamic allocation for (colp = (PXMLCOL)Columns; colp; colp = (PXMLCOL)colp->GetNext()) if (!colp->IsSpecial()) // Not a pseudo column @@ -671,7 +680,10 @@ void TDBXML::SetNodeAttr(PGLOBAL g, char *attr, PXNODE node) int TDBXML::Cardinality(PGLOBAL g) { if (!g) - return (Xpand || Coltype == 2) ? 0 : 1; + return (Multiple || Xpand || Coltype == 2) ? 0 : 1; + + if (Multiple) + return 10; if (Nrow < 0) if (Initialize(g)) @@ -685,8 +697,13 @@ int TDBXML::Cardinality(PGLOBAL g) /***********************************************************************/ int TDBXML::GetMaxSize(PGLOBAL g) { - if (MaxSize < 0) - MaxSize = Cardinality(g) * ((Xpand) ? Limit : 1); + if (MaxSize < 0) { + if (!Multiple) + MaxSize = Cardinality(g) * ((Xpand) ? Limit : 1); + else + MaxSize = 10; + + } // endif MaxSize return MaxSize; } // end of GetMaxSize @@ -952,6 +969,34 @@ void TDBXML::CloseDB(PGLOBAL g) Docp->CloseDoc(g, To_Xb); } // endif docp + if (Multiple) { + // Reset all constants to start a new parse + Docp = NULL; + Root = NULL; + Curp = NULL; + DBnode = NULL; + TabNode = NULL; + RowNode = NULL; + ColNode = NULL; + Nlist = NULL; + Clist = NULL; + To_Xb = NULL; + Colp = NULL; + Changed = false; + Checked = false; + NextSame = false; + NewRow = false; + Hasnod = false; + Write = false; +// Bufdone = false; + Nodedone = false; + Void = false; + Nrow = -1; + Irow = Header - 1; + Nsub = 0; + N = 0; + } // endif Multiple + } // end of CloseDB // ------------------------ XMLCOL functions ---------------------------- diff --git a/storage/connect/tabxml.h b/storage/connect/tabxml.h index 5aa038530c7..817bea45b3b 100644 --- a/storage/connect/tabxml.h +++ b/storage/connect/tabxml.h @@ -139,6 +139,7 @@ class DllExport TDBXML : public TDBASE { int Coltype; // Default column type int Limit; // Limit of multiple values int Header; // n first rows are header rows + int Multiple; // If multiple files int Nrow; // The table cardinality int Irow; // The current row index int Nsub; // The current subrow index diff --git a/storage/connect/user_connect.cc b/storage/connect/user_connect.cc index 877f612fc0a..b778d3f0883 100644 --- a/storage/connect/user_connect.cc +++ b/storage/connect/user_connect.cc @@ -146,6 +146,7 @@ bool user_connect::CheckCleanup(void) PlugSubSet(g, g->Sarea, g->Sarea_Size); g->Xchk = NULL; g->Createas = 0; + g->Alchecked = 0; last_query_id= thdp->query_id; if (xtrace) diff --git a/storage/connect/valblk.cpp b/storage/connect/valblk.cpp index bef5d6ef716..c0127072896 100644 --- a/storage/connect/valblk.cpp +++ b/storage/connect/valblk.cpp @@ -1,7 +1,7 @@ /************ Valblk C++ Functions Source Code File (.CPP) *************/ -/* Name: VALBLK.CPP Version 2.0 */ +/* Name: VALBLK.CPP Version 2.1 */ /* */ -/* (C) Copyright to the author Olivier BERTRAND 2005-2013 */ +/* (C) Copyright to the author Olivier BERTRAND 2005-2014 */ /* */ /* This file contains the VALBLK and derived classes functions. */ /* Second family is VALBLK, representing simple suballocated arrays */ @@ -236,6 +236,23 @@ void TYPBLK<TYPE>::Init(PGLOBAL g, bool check) Global = g; } // end of Init +/***********************************************************************/ +/* TYPVAL GetCharString: get string representation of a typed value. */ +/***********************************************************************/ +template <class TYPE> +char *TYPBLK<TYPE>::GetCharString(char *p, int n) + { + sprintf(p, Fmt, Typp[n]); + return p; + } // end of GetCharString + +template <> +char *TYPBLK<double>::GetCharString(char *p, int n) + { + sprintf(p, Fmt, Prec, Typp[n]); + return p; + } // end of GetCharString + /***********************************************************************/ /* Set one value in a block. */ /***********************************************************************/ @@ -677,6 +694,14 @@ double CHRBLK::GetFloatValue(int n) return atof((char *)GetValPtrEx(n)); } // end of GetFloatValue +/***********************************************************************/ +/* STRING GetCharString: get string representation of a char value. */ +/***********************************************************************/ +char *CHRBLK::GetCharString(char *p, int n) + { + return (char *)GetValPtrEx(n); + } // end of GetCharString + /***********************************************************************/ /* Set one value in a block. */ /***********************************************************************/ @@ -1185,6 +1210,22 @@ bool DATBLK::SetFormat(PGLOBAL g, PSZ fmt, int len, int year) return false; } // end of SetFormat +/***********************************************************************/ +/* DTVAL GetCharString: get string representation of a date value. */ +/***********************************************************************/ +char *DATBLK::GetCharString(char *p, int n) + { + char *vp; + + if (Dvalp) { + Dvalp->SetValue(Typp[n]); + vp = Dvalp->GetCharString(p); + } else + vp = TYPBLK<int>::GetCharString(p, n); + + return vp; + } // end of GetCharString + /***********************************************************************/ /* Set one value in a block from a char string. */ /***********************************************************************/ diff --git a/storage/connect/valblk.h b/storage/connect/valblk.h index debeb0669b0..1edfe7f76b4 100644 --- a/storage/connect/valblk.h +++ b/storage/connect/valblk.h @@ -1,7 +1,7 @@ /*************** Valblk H Declares Source Code File (.H) ***************/ -/* Name: VALBLK.H Version 2.0 */ +/* Name: VALBLK.H Version 2.1 */ /* */ -/* (C) Copyright to the author Olivier BERTRAND 2005-2013 */ +/* (C) Copyright to the author Olivier BERTRAND 2005-2014 */ /* */ /* This file contains the VALBLK and derived classes declares. */ /***********************************************************************/ @@ -58,6 +58,7 @@ class VALBLK : public BLOCK { virtual longlong GetBigintValue(int n) = 0; virtual ulonglong GetUBigintValue(int n) = 0; virtual double GetFloatValue(int n) = 0; + virtual char *GetCharString(char *p, int n) = 0; virtual void ReAlloc(void *mp, int n) {Blkp = mp; Nval = n;} virtual void Reset(int n) = 0; virtual bool SetFormat(PGLOBAL g, PSZ fmt, int len, int year = 0); @@ -133,6 +134,7 @@ class TYPBLK : public VALBLK { virtual longlong GetBigintValue(int n) {return (longlong)Typp[n];} virtual ulonglong GetUBigintValue(int n) {return (ulonglong)Typp[n];} virtual double GetFloatValue(int n) {return (double)Typp[n];} + virtual char *GetCharString(char *p, int n); virtual void Reset(int n) {Typp[n] = 0;} // Methods @@ -199,6 +201,7 @@ class CHRBLK : public VALBLK { virtual longlong GetBigintValue(int n); virtual ulonglong GetUBigintValue(int n); virtual double GetFloatValue(int n); + virtual char *GetCharString(char *p, int n); virtual void Reset(int n); virtual void SetPrec(int p) {Ci = (p != 0);} virtual bool IsCi(void) {return Ci;} @@ -252,6 +255,7 @@ class STRBLK : public VALBLK { virtual longlong GetBigintValue(int n); virtual ulonglong GetUBigintValue(int n); virtual double GetFloatValue(int n) {return atof(Strp[n]);} + virtual char *GetCharString(char *p, int n) {return Strp[n];} virtual void Reset(int n) {Strp[n] = NULL;} // Methods @@ -286,10 +290,11 @@ class DATBLK : public TYPBLK<int> { DATBLK(void *mp, int size); // Implementation - virtual bool SetFormat(PGLOBAL g, PSZ fmt, int len, int year = 0); + virtual bool SetFormat(PGLOBAL g, PSZ fmt, int len, int year = 0); + virtual char *GetCharString(char *p, int n); // Methods - virtual void SetValue(PSZ sp, int n); + virtual void SetValue(PSZ sp, int n); protected: // Members diff --git a/storage/connect/value.cpp b/storage/connect/value.cpp index 65a08ba277e..8a839f3b50b 100644 --- a/storage/connect/value.cpp +++ b/storage/connect/value.cpp @@ -1,7 +1,7 @@ /************* Value C++ Functions Source Code File (.CPP) *************/ -/* Name: VALUE.CPP Version 2.3 */ +/* Name: VALUE.CPP Version 2.4 */ /* */ -/* (C) Copyright to the author Olivier BERTRAND 2001-2013 */ +/* (C) Copyright to the author Olivier BERTRAND 2001-2014 */ /* */ /* This file contains the VALUE and derived classes family functions. */ /* These classes contain values of different types. They are used so */ @@ -1142,7 +1142,11 @@ void TYPVAL<PSZ>::SetValue_psz(PSZ s) void TYPVAL<PSZ>::SetValue_pvblk(PVBLK blk, int n) { // STRBLK's can return a NULL pointer - SetValue_psz(blk->GetCharValue(n)); + PSZ vp = blk->GetCharString(Strp, n); + + if (vp != Strp) + SetValue_psz(vp); + } // end of SetValue_pvblk /***********************************************************************/ diff --git a/storage/connect/xtable.h b/storage/connect/xtable.h index 174ceb19731..8884860cb5b 100644 --- a/storage/connect/xtable.h +++ b/storage/connect/xtable.h @@ -1,7 +1,7 @@ /**************** Table H Declares Source Code File (.H) ***************/ -/* Name: TABLE.H Version 2.2 */ +/* Name: TABLE.H Version 2.3 */ /* */ -/* (C) Copyright to the author Olivier BERTRAND 1999-2012 */ +/* (C) Copyright to the author Olivier BERTRAND 1999-2014 */ /* */ /* This file contains the TBX, OPJOIN and TDB class definitions. */ /***********************************************************************/ @@ -185,15 +185,7 @@ class DllExport TDBASE : public TDB { virtual bool SetRecpos(PGLOBAL g, int recpos); virtual bool IsReadOnly(void) {return Read_Only;} virtual bool IsView(void) {return FALSE;} - virtual CHARSET_INFO *data_charset() - { - /* - If no DATA_CHARSET is specified, we assume that character - set of the remote data is the same with CHARACTER SET - definition of the SQL column. - */ - return m_data_charset ? m_data_charset : &my_charset_bin; - } + virtual CHARSET_INFO *data_charset(void); virtual int GetProgMax(PGLOBAL g) {return GetMaxSize(g);} virtual int GetProgCur(void) {return GetRecpos();} virtual PSZ GetFile(PGLOBAL g) {return "Not a file";} @@ -229,7 +221,7 @@ class DllExport TDBASE : public TDB { /***********************************************************************/ /* The abstract base class declaration for the catalog tables. */ /***********************************************************************/ -class TDBCAT : public TDBASE { +class DllExport TDBCAT : public TDBASE { friend class CATCOL; public: // Constructor @@ -268,7 +260,7 @@ class TDBCAT : public TDBASE { /***********************************************************************/ /* Class CATCOL: ODBC info column. */ /***********************************************************************/ -class CATCOL : public COLBLK { +class DllExport CATCOL : public COLBLK { friend class TDBCAT; public: // Constructors -- 2.30.9