summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOlivier Bertrand <bertrandop@gmail.com>2014-04-19 11:11:30 +0200
committerOlivier Bertrand <bertrandop@gmail.com>2014-04-19 11:11:30 +0200
commit812520315318e358d2d9daf9ca709578af1efe40 (patch)
treed5dff4f4c06aa4554707a6ad717dc73a576313d0
parentcc7a08c9410335237e6c19f84d9c5d08938b8e8a (diff)
parentb43e82dce63c07abe8de740b3bf18a33600ccac0 (diff)
downloadmariadb-git-812520315318e358d2d9daf9ca709578af1efe40.tar.gz
- Commit merged files
modified: storage/connect/CMakeLists.txt storage/connect/connect.h storage/connect/global.h storage/connect/ha_connect.cc storage/connect/ha_connect.h storage/connect/myconn.cpp storage/connect/myconn.h storage/connect/mysql-test/connect/r/pivot.result storage/connect/mysql-test/connect/suite.pm storage/connect/mysql-test/connect/t/pivot.test storage/connect/myutil.cpp storage/connect/osutil.c storage/connect/plgdbsem.h storage/connect/plugutil.c storage/connect/tabmysql.cpp storage/connect/tabpivot.cpp storage/connect/tabutil.cpp storage/connect/user_connect.cc storage/connect/valblk.cpp storage/connect/valblk.h storage/connect/value.cpp storage/connect/value.h storage/connect/xindex.cpp storage/connect/xindex.h
-rw-r--r--storage/connect/CMakeLists.txt14
-rw-r--r--storage/connect/connect.h3
-rw-r--r--storage/connect/global.h517
-rw-r--r--storage/connect/ha_connect.cc11532
-rw-r--r--storage/connect/ha_connect.h1061
-rw-r--r--storage/connect/myconn.cpp55
-rw-r--r--storage/connect/myconn.h2
-rw-r--r--storage/connect/mysql-test/connect/r/pivot.result2
-rw-r--r--storage/connect/mysql-test/connect/suite.pm5
-rw-r--r--storage/connect/mysql-test/connect/t/pivot.test326
-rw-r--r--storage/connect/myutil.cpp72
-rw-r--r--storage/connect/osutil.c20
-rw-r--r--storage/connect/plgdbsem.h1197
-rw-r--r--storage/connect/plugutil.c41
-rw-r--r--storage/connect/tabmysql.cpp7
-rw-r--r--storage/connect/tabpivot.cpp33
-rw-r--r--storage/connect/tabutil.cpp41
-rw-r--r--storage/connect/user_connect.cc18
-rw-r--r--storage/connect/valblk.cpp39
-rw-r--r--storage/connect/valblk.h604
-rw-r--r--storage/connect/value.cpp431
-rw-r--r--storage/connect/value.h723
-rwxr-xr-xstorage/connect/xindex.cpp101
-rw-r--r--storage/connect/xindex.h22
24 files changed, 8877 insertions, 7989 deletions
diff --git a/storage/connect/CMakeLists.txt b/storage/connect/CMakeLists.txt
index 20fa68ea5a5..f8db000a486 100644
--- a/storage/connect/CMakeLists.txt
+++ b/storage/connect/CMakeLists.txt
@@ -123,7 +123,7 @@ IF(WIN32)
# /MP option of the Microsoft compiler does not work well with COM #import
string(REPLACE "/MP" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
string(REPLACE "/MP" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
-
+
OPTION(CONNECT_WITH_MSXML "Compile CONNECT storage engine with MSXML support" ON)
IF(CONNECT_WITH_MSXML)
find_library(MSXML_LIBRARY
@@ -264,6 +264,17 @@ int main() {
ENDIF(UNIX)
ENDIF(CONNECT_WITH_ODBC)
+
+#
+# XMAP
+#
+
+OPTION(CONNECT_WITH_XMAP "Compile CONNECT storage engine with index file mapping support" ON)
+
+IF(CONNECT_WITH_XMAP)
+ add_definitions(-DXMAP)
+ENDIF(CONNECT_WITH_XMAP)
+
#
# Plugin definition
#
@@ -271,6 +282,7 @@ ENDIF(CONNECT_WITH_ODBC)
MYSQL_ADD_PLUGIN(connect ${CONNECT_SOURCES}
STORAGE_ENGINE
COMPONENT connect-engine
+ RECOMPILE_FOR_EMBEDDED
LINK_LIBRARIES ${ZLIB_LIBRARY} ${XML_LIBRARY} ${ICONV_LIBRARY}
${ODBC_LIBRARY} ${IPHLPAPI_LIBRARY})
diff --git a/storage/connect/connect.h b/storage/connect/connect.h
index be423fcb575..380da7c29b9 100644
--- a/storage/connect/connect.h
+++ b/storage/connect/connect.h
@@ -36,8 +36,7 @@ bool CntRewindTable(PGLOBAL g, PTDB tdbp);
int CntCloseTable(PGLOBAL g, PTDB tdbp);
int CntIndexInit(PGLOBAL g, PTDB tdbp, int id);
RCODE CntReadNext(PGLOBAL g, PTDB tdbp);
-RCODE CntIndexRead(PGLOBAL g, PTDB, OPVAL op, const void *k, int n,
- bool mrr = false);
+RCODE CntIndexRead(PGLOBAL g, PTDB, OPVAL op, const void *k, int n, bool mrr);
RCODE CntWriteRow(PGLOBAL g, PTDB tdbp);
RCODE CntUpdateRow(PGLOBAL g, PTDB tdbp);
RCODE CntDeleteRow(PGLOBAL g, PTDB tdbp, bool all);
diff --git a/storage/connect/global.h b/storage/connect/global.h
index 4f94651b0b5..d7cab0f543f 100644
--- a/storage/connect/global.h
+++ b/storage/connect/global.h
@@ -1,258 +1,259 @@
-/***********************************************************************/
-/* GLOBAL.H: Declaration file used by all CONNECT implementations. */
-/* (C) Copyright Olivier Bertrand 1993-2012 */
-/***********************************************************************/
-
-/***********************************************************************/
-/* Included C-definition files common to all Plug routines */
-/***********************************************************************/
-#include <string.h> /* String manipulation declares */
-#include <stdlib.h> /* C standard library */
-#include <ctype.h> /* C language specific types */
-#include <stdio.h> /* FOPEN_MAX declaration */
-#include <time.h> /* time_t type declaration */
-#include <setjmp.h> /* Long jump declarations */
-
-#if defined(WIN32) && !defined(NOEX)
-#define DllExport __declspec( dllexport )
-#else // !WIN32
-#define DllExport
-#endif // !WIN32
-
-#if defined(DOMDOC_SUPPORT) || defined(LIBXML2_SUPPORT)
-#define XML_SUPPORT 1
-#endif
-
-#if defined(XMSG)
-// Definition used to read messages from message file.
-#include "msgid.h"
-#define MSG(I) PlugReadMessage(NULL, MSG_##I, #I)
-#define STEP(I) PlugReadMessage(g, MSG_##I, #I)
-#elif defined(NEWMSG)
-// Definition used to get messages from resource.
-#include "msgid.h"
-#define MSG(I) PlugGetMessage(NULL, MSG_##I)
-#define STEP(I) PlugGetMessage(g, MSG_##I)
-#else // !XMSG and !NEWMSG
-// Definition used to replace messages ID's by their definition.
-#include "messages.h"
-#define MSG(I) MSG_##I
-#define STEP(I) MSG_##I
-#endif // !XMSG and !NEWMSG
-
-#if defined(WIN32)
-#define CRLF 2
-#else // !WIN32
-#define CRLF 1
-#endif // !WIN32
-
-/***********************************************************************/
-/* Miscellaneous Constants */
-/***********************************************************************/
-#define NO_IVAL -95684275 /* Used by GetIntegerOption */
-#define VMLANG 370 /* Size of olf VM lang blocks */
-#define MAX_JUMP 24 /* Maximum jump level number */
-#define MAX_STR 1024 /* Maximum string length */
-#define STR_SIZE 501 /* Length of char strings. */
-#define STD_INPUT 0 /* Standard language input */
-#define STD_OUTPUT 1 /* Standard language output */
-#define ERROR_OUTPUT 2 /* Error message output */
-#define DEBUG_OUTPUT 3 /* Debug info output */
-#define PROMPT_OUTPUT 4 /* Prompt message output */
-#define COPY_OUTPUT 5 /* Copy of language input */
-#define STD_MSG 6 /* System message file */
-#define DEBUG_MSG 7 /* Debug message file */
-#define DUMMY 0 /* Dummy file index in Ldm block */
-#define STDIN 1 /* stdin file index in Ldm block */
-#define STDOUT 2 /* stdout file index in Ldm block */
-#define STDERR 3 /* stderr file index in Ldm block */
-#define STDEBUG 4 /* debug file index in Ldm block */
-#define STDPRN 5 /* stdprn file index in Ldm block */
-#define STDFREE 6 /* Free file index in Ldm block */
-
-#define TYPE_SEM -2 /* Returned semantic function */
-#define TYPE_DFONC -2 /* Indirect sem ref in FPARM */
-#define TYPE_VOID -1
-#define TYPE_SBPAR -1 /* Phrase reference in FPARM */
-#define TYPE_SEMX 0 /* Initial semantic function type? */
-#define TYPE_ERROR 0
-#define TYPE_STRING 1
-#define TYPE_DOUBLE 2
-#define TYPE_SHORT 3
-#define TYPE_TINY 4
-#define TYPE_BIGINT 5
-#define TYPE_LIST 6
-#define TYPE_INT 7
-#define TYPE_DECIM 9
-
-#if defined(OS32)
- #define SYS_STAMP "OS32"
-#elif defined(UNIX) || defined(LINUX) || defined(UNIV_LINUX)
- #define SYS_STAMP "UNIX"
-#elif defined(OS16)
- #define SYS_STAMP "OS16"
-#elif defined(DOSR)
- #define SYS_STAMP "DOSR"
-#elif defined(WIN)
- #define SYS_STAMP "WIN1"
-#elif defined(WIN32)
- #define SYS_STAMP "WIN2"
-#else
- #define SYS_STAMP "XXXX"
-#endif
-
-#if defined(__cplusplus)
-extern "C" {
-#endif
-
-/***********************************************************************/
-/* Static variables */
-/***********************************************************************/
-#if defined(STORAGE)
- char sys_stamp[4] = SYS_STAMP;
-#else
- extern char sys_stamp[];
-#endif
-
-/***********************************************************************/
-/* File-Selection Indicators */
-/***********************************************************************/
-#define PAT_LOG "log"
-
-#if defined(UNIX) || defined(LINUX) || defined(UNIV_LINUX)
- /*********************************************************************/
- /* printf does not accept null pointer for %s target. */
- /*********************************************************************/
- #define SVP(S) ((S) ? S : "<null>")
-#else
- /*********************************************************************/
- /* printf accepts null pointer for %s target. */
- /*********************************************************************/
- #define SVP(S) S
-#endif
-
-#if defined(STORAGE)
- FILE *debug;
-#else
- extern FILE *debug;
-#endif
-
-
-/***********************************************************************/
-/* General purpose type definitions. */
-/***********************************************************************/
-#include "os.h"
-
-typedef uint OFFSET;
-typedef char NAME[9];
-
-typedef struct {
- ushort Length;
- char String[2];
- } VARSTR;
-
-#if !defined(PGLOBAL_DEFINED)
-typedef struct _global *PGLOBAL;
-#define PGLOBAL_DEFINED
-#endif
-typedef struct _globplg *PGS;
-typedef struct _activity *PACTIVITY;
-typedef struct _parm *PPARM;
-
-/***********************************************************************/
-/* Segment Sub-Allocation block structure declares. */
-/* Next block is an implementation dependent segment suballoc save */
-/* structure used to keep the suballocation system offsets and to */
-/* restore them if needed. This scheme implies that no SubFree be used */
-/***********************************************************************/
-typedef struct { /* Plug Area SubAlloc header */
- OFFSET To_Free; /* Offset of next free block */
- uint FreeBlk; /* Size of remaining free memory */
- } POOLHEADER, *PPOOLHEADER;
-
-/***********************************************************************/
-/* Language block. Containing all global information for the language */
-/* this block is saved and retrieved with the language. Information */
-/* in this block can be set and modified under Grammar editing. */
-/***********************************************************************/
-#if defined(BIT64)
-typedef int TIME_T; /* Lang block size must not change */
-#else // BIT32
-typedef time_t TIME_T; /* time_t */
-#endif // BIT32
-
-typedef struct {
- uint Memsize;
- uint Size;
- } AREADEF;
-
-typedef struct Lang_block {
- NAME LangName; /* Language name */
- NAME Application; /* Application name */
- } LANG, *PLANG;
-
-/***********************************************************************/
-/* Application block. It contains all global information for the */
-/* current parse and execution using the corresponding language. */
-/* This block is dynamically allocated and set at language init. */
-/***********************************************************************/
-typedef struct _activity { /* Describes activity and language */
- void *Aptr; /* Points to user work area(s) */
- NAME Ap_Name; /* Current application name */
- } ACTIVITY;
-
-/*---------------- UNIT ?????????? VERSION ? ----------------------*/
-typedef struct _parm {
- void *Value;
- short Type, Domain;
- PPARM Next;
- } PARM;
-
-/***********************************************************************/
-/* Global Structure Block. This block contains, or points to, all */
-/* information used by CONNECT tables. Passed as an argument */
-/* to any routine allows it to have access to the entire information */
-/* currently available for the whole set of loaded languages. */
-/***********************************************************************/
-typedef struct _global { /* Global structure */
- void *Sarea; /* Points to work area */
- uint Sarea_Size; /* Work area size */
- PACTIVITY Activityp, ActivityStart;
- char Message[MAX_STR];
- int Createas; /* To pass info to created table */
- void *Xchk; /* indexes in create/alter */
- short Alchecked; /* Checked for ALTER */
- short Mrr; /* True when doing mrr */
- short Trace;
- int jump_level;
- jmp_buf jumper[MAX_JUMP + 2];
- } GLOBAL;
-
-/***********************************************************************/
-/* Exported routine declarations. */
-/***********************************************************************/
-#if defined(XMSG)
-DllExport char *PlugReadMessage(PGLOBAL, int, char *);
-#elif defined(NEWMSG)
-DllExport char *PlugGetMessage(PGLOBAL, int);
-#endif // XMSG || NEWMSG
-#if defined(WIN32)
-DllExport short GetLineLength(PGLOBAL); // Console line length
-#endif // WIN32
-DllExport PGLOBAL PlugInit(LPCSTR, uint); // Plug global initialization
-DllExport int PlugExit(PGLOBAL); // Plug global termination
-DllExport LPSTR PlugRemoveType(LPSTR, LPCSTR);
-DllExport LPCSTR PlugSetPath(LPSTR to, LPCSTR prefix, LPCSTR name, LPCSTR dir);
-DllExport BOOL PlugIsAbsolutePath(LPCSTR path);
-DllExport void *PlugAllocMem(PGLOBAL, uint);
-DllExport BOOL PlugSubSet(PGLOBAL, void *, uint);
-DllExport void *PlugSubAlloc(PGLOBAL, void *, size_t);
-DllExport char *PlugDup(PGLOBAL g, const char *str);
-DllExport void *MakePtr(void *, OFFSET);
-DllExport void htrc(char const *fmt, ...);
-
-#if defined(__cplusplus)
-} // extern "C"
-#endif
-
-/*-------------------------- End of Global.H --------------------------*/
+/***********************************************************************/
+/* GLOBAL.H: Declaration file used by all CONNECT implementations. */
+/* (C) Copyright Olivier Bertrand 1993-2014 */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Included C-definition files common to all Plug routines */
+/***********************************************************************/
+#include <string.h> /* String manipulation declares */
+#include <stdlib.h> /* C standard library */
+#include <ctype.h> /* C language specific types */
+#include <stdio.h> /* FOPEN_MAX declaration */
+#include <time.h> /* time_t type declaration */
+#include <setjmp.h> /* Long jump declarations */
+
+#if defined(WIN32) && !defined(NOEX)
+#define DllExport __declspec( dllexport )
+#else // !WIN32
+#define DllExport
+#endif // !WIN32
+
+#if defined(DOMDOC_SUPPORT) || defined(LIBXML2_SUPPORT)
+#define XML_SUPPORT 1
+#endif
+
+#if defined(XMSG)
+// Definition used to read messages from message file.
+#include "msgid.h"
+#define MSG(I) PlugReadMessage(NULL, MSG_##I, #I)
+#define STEP(I) PlugReadMessage(g, MSG_##I, #I)
+#elif defined(NEWMSG)
+// Definition used to get messages from resource.
+#include "msgid.h"
+#define MSG(I) PlugGetMessage(NULL, MSG_##I)
+#define STEP(I) PlugGetMessage(g, MSG_##I)
+#else // !XMSG and !NEWMSG
+// Definition used to replace messages ID's by their definition.
+#include "messages.h"
+#define MSG(I) MSG_##I
+#define STEP(I) MSG_##I
+#endif // !XMSG and !NEWMSG
+
+#if defined(WIN32)
+#define CRLF 2
+#else // !WIN32
+#define CRLF 1
+#endif // !WIN32
+
+/***********************************************************************/
+/* Miscellaneous Constants */
+/***********************************************************************/
+#define NO_IVAL -95684275 /* Used by GetIntegerOption */
+#define VMLANG 370 /* Size of olf VM lang blocks */
+#define MAX_JUMP 24 /* Maximum jump level number */
+#define MAX_STR 1024 /* Maximum string length */
+#define STR_SIZE 501 /* Length of char strings. */
+#define STD_INPUT 0 /* Standard language input */
+#define STD_OUTPUT 1 /* Standard language output */
+#define ERROR_OUTPUT 2 /* Error message output */
+#define DEBUG_OUTPUT 3 /* Debug info output */
+#define PROMPT_OUTPUT 4 /* Prompt message output */
+#define COPY_OUTPUT 5 /* Copy of language input */
+#define STD_MSG 6 /* System message file */
+#define DEBUG_MSG 7 /* Debug message file */
+#define DUMMY 0 /* Dummy file index in Ldm block */
+#define STDIN 1 /* stdin file index in Ldm block */
+#define STDOUT 2 /* stdout file index in Ldm block */
+#define STDERR 3 /* stderr file index in Ldm block */
+#define STDEBUG 4 /* debug file index in Ldm block */
+#define STDPRN 5 /* stdprn file index in Ldm block */
+#define STDFREE 6 /* Free file index in Ldm block */
+
+#define TYPE_SEM -2 /* Returned semantic function */
+#define TYPE_DFONC -2 /* Indirect sem ref in FPARM */
+#define TYPE_VOID -1
+#define TYPE_SBPAR -1 /* Phrase reference in FPARM */
+#define TYPE_SEMX 0 /* Initial semantic function type? */
+#define TYPE_ERROR 0
+#define TYPE_STRING 1
+#define TYPE_DOUBLE 2
+#define TYPE_SHORT 3
+#define TYPE_TINY 4
+#define TYPE_BIGINT 5
+#define TYPE_LIST 6
+#define TYPE_INT 7
+#define TYPE_DECIM 9
+#define TYPE_BIN 10
+
+#if defined(OS32)
+ #define SYS_STAMP "OS32"
+#elif defined(UNIX) || defined(LINUX) || defined(UNIV_LINUX)
+ #define SYS_STAMP "UNIX"
+#elif defined(OS16)
+ #define SYS_STAMP "OS16"
+#elif defined(DOSR)
+ #define SYS_STAMP "DOSR"
+#elif defined(WIN)
+ #define SYS_STAMP "WIN1"
+#elif defined(WIN32)
+ #define SYS_STAMP "WIN2"
+#else
+ #define SYS_STAMP "XXXX"
+#endif
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/***********************************************************************/
+/* Static variables */
+/***********************************************************************/
+#if defined(STORAGE)
+ char sys_stamp[4] = SYS_STAMP;
+#else
+ extern char sys_stamp[];
+#endif
+
+/***********************************************************************/
+/* File-Selection Indicators */
+/***********************************************************************/
+#define PAT_LOG "log"
+
+#if defined(UNIX) || defined(LINUX) || defined(UNIV_LINUX)
+ /*********************************************************************/
+ /* printf does not accept null pointer for %s target. */
+ /*********************************************************************/
+ #define SVP(S) ((S) ? S : "<null>")
+#else
+ /*********************************************************************/
+ /* printf accepts null pointer for %s target. */
+ /*********************************************************************/
+ #define SVP(S) S
+#endif
+
+#if defined(STORAGE)
+ FILE *debug;
+#else
+ extern FILE *debug;
+#endif
+
+
+/***********************************************************************/
+/* General purpose type definitions. */
+/***********************************************************************/
+#include "os.h"
+
+typedef uint OFFSET;
+typedef char NAME[9];
+
+typedef struct {
+ ushort Length;
+ char String[2];
+ } VARSTR;
+
+#if !defined(PGLOBAL_DEFINED)
+typedef struct _global *PGLOBAL;
+#define PGLOBAL_DEFINED
+#endif
+typedef struct _globplg *PGS;
+typedef struct _activity *PACTIVITY;
+typedef struct _parm *PPARM;
+
+/***********************************************************************/
+/* Segment Sub-Allocation block structure declares. */
+/* Next block is an implementation dependent segment suballoc save */
+/* structure used to keep the suballocation system offsets and to */
+/* restore them if needed. This scheme implies that no SubFree be used */
+/***********************************************************************/
+typedef struct { /* Plug Area SubAlloc header */
+ OFFSET To_Free; /* Offset of next free block */
+ uint FreeBlk; /* Size of remaining free memory */
+ } POOLHEADER, *PPOOLHEADER;
+
+/***********************************************************************/
+/* Language block. Containing all global information for the language */
+/* this block is saved and retrieved with the language. Information */
+/* in this block can be set and modified under Grammar editing. */
+/***********************************************************************/
+#if defined(BIT64)
+typedef int TIME_T; /* Lang block size must not change */
+#else // BIT32
+typedef time_t TIME_T; /* time_t */
+#endif // BIT32
+
+typedef struct {
+ uint Memsize;
+ uint Size;
+ } AREADEF;
+
+typedef struct Lang_block {
+ NAME LangName; /* Language name */
+ NAME Application; /* Application name */
+ } LANG, *PLANG;
+
+/***********************************************************************/
+/* Application block. It contains all global information for the */
+/* current parse and execution using the corresponding language. */
+/* This block is dynamically allocated and set at language init. */
+/***********************************************************************/
+typedef struct _activity { /* Describes activity and language */
+ void *Aptr; /* Points to user work area(s) */
+ NAME Ap_Name; /* Current application name */
+ } ACTIVITY;
+
+/*---------------- UNIT ?????????? VERSION ? ----------------------*/
+typedef struct _parm {
+ void *Value;
+ short Type, Domain;
+ PPARM Next;
+ } PARM;
+
+/***********************************************************************/
+/* Global Structure Block. This block contains, or points to, all */
+/* information used by CONNECT tables. Passed as an argument */
+/* to any routine allows it to have access to the entire information */
+/* currently available for the whole set of loaded languages. */
+/***********************************************************************/
+typedef struct _global { /* Global structure */
+ void *Sarea; /* Points to work area */
+ uint Sarea_Size; /* Work area size */
+ PACTIVITY Activityp, ActivityStart;
+ char Message[MAX_STR];
+ int Createas; /* To pass info to created table */
+ void *Xchk; /* indexes in create/alter */
+ short Alchecked; /* Checked for ALTER */
+ short Mrr; /* True when doing mrr */
+ short Trace;
+ int jump_level;
+ jmp_buf jumper[MAX_JUMP + 2];
+ } GLOBAL;
+
+/***********************************************************************/
+/* Exported routine declarations. */
+/***********************************************************************/
+#if defined(XMSG)
+DllExport char *PlugReadMessage(PGLOBAL, int, char *);
+#elif defined(NEWMSG)
+DllExport char *PlugGetMessage(PGLOBAL, int);
+#endif // XMSG || NEWMSG
+#if defined(WIN32)
+DllExport short GetLineLength(PGLOBAL); // Console line length
+#endif // WIN32
+DllExport PGLOBAL PlugInit(LPCSTR, uint); // Plug global initialization
+DllExport int PlugExit(PGLOBAL); // Plug global termination
+DllExport LPSTR PlugRemoveType(LPSTR, LPCSTR);
+DllExport LPCSTR PlugSetPath(LPSTR to, LPCSTR prefix, LPCSTR name, LPCSTR dir);
+DllExport BOOL PlugIsAbsolutePath(LPCSTR path);
+DllExport void *PlugAllocMem(PGLOBAL, uint);
+DllExport BOOL PlugSubSet(PGLOBAL, void *, uint);
+DllExport void *PlugSubAlloc(PGLOBAL, void *, size_t);
+DllExport char *PlugDup(PGLOBAL g, const char *str);
+DllExport void *MakePtr(void *, OFFSET);
+DllExport void htrc(char const *fmt, ...);
+
+#if defined(__cplusplus)
+} // extern "C"
+#endif
+
+/*-------------------------- End of Global.H --------------------------*/
diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc
index d557f8e6bce..24a9ff36b98 100644
--- a/storage/connect/ha_connect.cc
+++ b/storage/connect/ha_connect.cc
@@ -1,5705 +1,5837 @@
-/* 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
- the Free Software Foundation; version 2 of the License.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/**
- @file ha_connect.cc
-
- @brief
- The ha_connect engine is a stubbed storage engine that enables to create tables
- based on external data. Principally they are based on plain files of many
- different types, but also on collections of such files, collection of tables,
- ODBC tables retrieving data from other DBMS having an ODBC server, and even
- virtual tables.
-
- @details
- ha_connect will let you create/open/delete tables, the created table can be
- done specifying an already existing file, the drop table command will just
- suppress the table definition but not the eventual data file.
- Indexes are not supported for all table types but data can be inserted,
- updated or deleted.
-
- You can enable the CONNECT storage engine in your build by doing the
- following during your build process:<br> ./configure
- --with-connect-storage-engine
-
- You can install the CONNECT handler as all other storage handlers.
-
- Once this is done, MySQL will let you create tables with:<br>
- CREATE TABLE <table name> (...) ENGINE=CONNECT;
-
- The example storage engine does not use table locks. It
- implements an example "SHARE" that is inserted into a hash by table
- name. This is not used yet.
-
- Please read the object definition in ha_connect.h before reading the rest
- of this file.
-
- @note
- This MariaDB CONNECT handler is currently an adaptation of the XDB handler
- that was written for MySQL version 4.1.2-alpha. Its overall design should
- be enhanced in the future to meet MariaDB requirements.
-
- @note
- It was written also from the Brian's ha_example handler and contains parts
- of it that are there but not currently used, such as table variables.
-
- @note
- When you create an CONNECT table, the MySQL Server creates a table .frm
- (format) file in the database directory, using the table name as the file
- name as is customary with MySQL. No other files are created. To get an idea
- of what occurs, here is an example select that would do a scan of an entire
- table:
-
- @code
- ha-connect::open
- ha_connect::store_lock
- ha_connect::external_lock
- ha_connect::info
- ha_connect::rnd_init
- ha_connect::extra
- ENUM HA_EXTRA_CACHE Cache record in HA_rrnd()
- ha_connect::rnd_next
- ha_connect::rnd_next
- ha_connect::rnd_next
- ha_connect::rnd_next
- ha_connect::rnd_next
- ha_connect::rnd_next
- ha_connect::rnd_next
- ha_connect::rnd_next
- ha_connect::rnd_next
- ha_connect::extra
- ENUM HA_EXTRA_NO_CACHE End caching of records (def)
- ha_connect::external_lock
- ha_connect::extra
- ENUM HA_EXTRA_RESET Reset database to after open
- @endcode
-
- Here you see that the connect storage engine has 9 rows called before
- rnd_next signals that it has reached the end of its data. Calls to
- ha_connect::extra() are hints as to what will be occuring to the request.
-
- Happy use!<br>
- -Olivier
-*/
-
-#ifdef USE_PRAGMA_IMPLEMENTATION
-#pragma implementation // gcc: Class implementation
-#endif
-
-#define MYSQL_SERVER 1
-#define DONT_DEFINE_VOID
-//#include "sql_partition.h"
-#include "sql_class.h"
-#include "create_options.h"
-#include "mysql_com.h"
-#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
-#undef OFFSET
-
-#define NOPARSE
-#if defined(UNIX)
-#include "osutil.h"
-#endif // UNIX
-#include "global.h"
-#include "plgdbsem.h"
-#if defined(ODBC_SUPPORT)
-#include "odbccat.h"
-#endif // ODBC_SUPPORT
-#if defined(MYSQL_SUPPORT)
-#include "xtable.h"
-#include "tabmysql.h"
-#endif // MYSQL_SUPPORT
-#include "filamdbf.h"
-#include "tabxcl.h"
-#include "tabfmt.h"
-#include "reldef.h"
-#include "tabcol.h"
-#include "xindex.h"
-#if defined(WIN32)
-#include <io.h>
-#include "tabwmi.h"
-#endif // WIN32
-#include "connect.h"
-#include "user_connect.h"
-#include "ha_connect.h"
-#include "mycat.h"
-#include "myutil.h"
-#include "preparse.h"
-#include "inihandl.h"
-#if defined(LIBXML2_SUPPORT)
-#include "libdoc.h"
-#endif // LIBXML2_SUPPORT
-#include "taboccur.h"
-#include "tabpivot.h"
-
-#define my_strupr(p) my_caseup_str(default_charset_info, (p));
-#define my_strlwr(p) my_casedn_str(default_charset_info, (p));
-#define my_stricmp(a,b) my_strcasecmp(default_charset_info, (a), (b))
-
-
-/***********************************************************************/
-/* Initialize the ha_connect static members. */
-/***********************************************************************/
-//efine CONNECT_INI "connect.ini"
-extern "C" {
- char version[]= "Version 1.02.0002 March 16, 2014";
-
-#if defined(XMSG)
- char msglang[]; // Default message language
-#endif
- int trace= 0; // The general trace value
-} // extern "C"
-
-static 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 handler *connect_create_handler(handlerton *hton,
- TABLE_SHARE *table,
- MEM_ROOT *mem_root);
-
-static int connect_assisted_discovery(handlerton *hton, THD* thd,
- TABLE_SHARE *table_s,
- HA_CREATE_INFO *info);
-
-static void update_connect_xtrace(MYSQL_THD thd,
- struct st_mysql_sys_var *var,
- void *var_ptr, const void *save)
-{
- xtrace= *(int *)save;
-//xtrace= *(int *)var_ptr= *(int *)save;
-} // end of update_connect_xtrace
-
-handlerton *connect_hton;
-
-/**
- CREATE TABLE option list (table options)
-
- These can be specified in the CREATE TABLE:
- CREATE TABLE ( ... ) {...here...}
-*/
-ha_create_table_option connect_table_option_list[]=
-{
- HA_TOPTION_STRING("TABLE_TYPE", type),
- HA_TOPTION_STRING("FILE_NAME", filename),
- HA_TOPTION_STRING("XFILE_NAME", optname),
-//HA_TOPTION_STRING("CONNECT_STRING", connect),
- HA_TOPTION_STRING("TABNAME", tabname),
- HA_TOPTION_STRING("TABLE_LIST", tablist),
- HA_TOPTION_STRING("DBNAME", dbname),
- HA_TOPTION_STRING("SEP_CHAR", separator),
- HA_TOPTION_STRING("QCHAR", qchar),
- HA_TOPTION_STRING("MODULE", module),
- HA_TOPTION_STRING("SUBTYPE", subtype),
- HA_TOPTION_STRING("CATFUNC", catfunc),
- HA_TOPTION_STRING("SRCDEF", srcdef),
- HA_TOPTION_STRING("COLIST", colist),
- HA_TOPTION_STRING("OPTION_LIST", oplist),
- HA_TOPTION_STRING("DATA_CHARSET", data_charset),
- HA_TOPTION_NUMBER("LRECL", lrecl, 0, 0, INT_MAX32, 1),
- HA_TOPTION_NUMBER("BLOCK_SIZE", elements, 0, 0, INT_MAX32, 1),
-//HA_TOPTION_NUMBER("ESTIMATE", estimate, 0, 0, INT_MAX32, 1),
- HA_TOPTION_NUMBER("MULTIPLE", multiple, 0, 0, 2, 1),
- HA_TOPTION_NUMBER("HEADER", header, 0, 0, 3, 1),
- HA_TOPTION_NUMBER("QUOTED", quoted, (ulonglong) -1, 0, 3, 1),
- HA_TOPTION_NUMBER("ENDING", ending, (ulonglong) -1, 0, INT_MAX32, 1),
- HA_TOPTION_NUMBER("COMPRESS", compressed, 0, 0, 2, 1),
-//HA_TOPTION_BOOL("COMPRESS", compressed, 0),
- HA_TOPTION_BOOL("MAPPED", mapped, 0),
- HA_TOPTION_BOOL("HUGE", huge, 0),
- HA_TOPTION_BOOL("SPLIT", split, 0),
- HA_TOPTION_BOOL("READONLY", readonly, 0),
- HA_TOPTION_BOOL("SEPINDEX", sepindex, 0),
- HA_TOPTION_END
-};
-
-
-/**
- CREATE TABLE option list (field options)
-
- These can be specified in the CREATE TABLE per field:
- CREATE TABLE ( field ... {...here...}, ... )
-*/
-ha_create_table_option connect_field_option_list[]=
-{
- HA_FOPTION_NUMBER("FLAG", offset, (ulonglong) -1, 0, INT_MAX32, 1),
- HA_FOPTION_NUMBER("MAX_DIST", freq, 0, 0, INT_MAX32, 1), // BLK_INDX
- HA_FOPTION_NUMBER("DISTRIB", opt, 0, 0, 2, 1), // used for BLK_INDX
- HA_FOPTION_NUMBER("FIELD_LENGTH", fldlen, 0, 0, INT_MAX32, 1),
- HA_FOPTION_STRING("DATE_FORMAT", dateformat),
- HA_FOPTION_STRING("FIELD_FORMAT", fieldformat),
- HA_FOPTION_STRING("SPECIAL", special),
- HA_FOPTION_END
-};
-
+/* 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
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/**
+ @file ha_connect.cc
+
+ @brief
+ The ha_connect engine is a stubbed storage engine that enables to create tables
+ based on external data. Principally they are based on plain files of many
+ different types, but also on collections of such files, collection of tables,
+ local or remote MySQL/MariaDB tables retrieved via MySQL API,
+ ODBC tables retrieving data from other DBMS having an ODBC server, and even
+ virtual tables.
+
+ @details
+ ha_connect will let you create/open/delete tables, the created table can be
+ done specifying an already existing file, the drop table command will just
+ suppress the table definition but not the eventual data file.
+ Indexes are not supported for all table types but data can be inserted,
+ updated or deleted.
+
+ You can enable the CONNECT storage engine in your build by doing the
+ following during your build process:<br> ./configure
+ --with-connect-storage-engine
+
+ You can install the CONNECT handler as all other storage handlers.
+
+ Once this is done, MySQL will let you create tables with:<br>
+ CREATE TABLE <table name> (...) ENGINE=CONNECT;
+
+ The example storage engine does not use table locks. It
+ implements an example "SHARE" that is inserted into a hash by table
+ name. This is not used yet.
+
+ Please read the object definition in ha_connect.h before reading the rest
+ of this file.
+
+ @note
+ This MariaDB CONNECT handler is currently an adaptation of the XDB handler
+ that was written for MySQL version 4.1.2-alpha. Its overall design should
+ be enhanced in the future to meet MariaDB requirements.
+
+ @note
+ It was written also from the Brian's ha_example handler and contains parts
+ of it that are there, such as table and system variables.
+
+ @note
+ When you create an CONNECT table, the MySQL Server creates a table .frm
+ (format) file in the database directory, using the table name as the file
+ name as is customary with MySQL.
+ For file based tables, if a file name is not specified, this is an inward
+ table. An empty file is made in the current data directory that you can
+ populate later like for other engine tables. This file modified on ALTER
+ and is deleted when dropping the table.
+ If a file name is specified, this in an outward table. The specified file
+ will be used as representing the table data and will not be modified or
+ deleted on command such as ALTER or DROP.
+ To get an idea of what occurs, here is an example select that would do
+ a scan of an entire table:
+
+ @code
+ ha-connect::open
+ ha_connect::store_lock
+ ha_connect::external_lock
+ ha_connect::info
+ ha_connect::rnd_init
+ ha_connect::extra
+ ENUM HA_EXTRA_CACHE Cache record in HA_rrnd()
+ ha_connect::rnd_next
+ ha_connect::rnd_next
+ ha_connect::rnd_next
+ ha_connect::rnd_next
+ ha_connect::rnd_next
+ ha_connect::rnd_next
+ ha_connect::rnd_next
+ ha_connect::rnd_next
+ ha_connect::rnd_next
+ ha_connect::extra
+ ENUM HA_EXTRA_NO_CACHE End caching of records (def)
+ ha_connect::external_lock
+ ha_connect::extra
+ ENUM HA_EXTRA_RESET Reset database to after open
+ @endcode
+
+ Here you see that the connect storage engine has 9 rows called before
+ rnd_next signals that it has reached the end of its data. Calls to
+ ha_connect::extra() are hints as to what will be occuring to the request.
+
+ Happy use!<br>
+ -Olivier
+*/
+
+#ifdef USE_PRAGMA_IMPLEMENTATION
+#pragma implementation // gcc: Class implementation
+#endif
+
+#define MYSQL_SERVER 1
+#define DONT_DEFINE_VOID
+//#include "sql_partition.h"
+#include "sql_class.h"
+#include "create_options.h"
+#include "mysql_com.h"
+#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
+#undef OFFSET
+
+#define NOPARSE
+#if defined(UNIX)
+#include "osutil.h"
+#endif // UNIX
+#include "global.h"
+#include "plgdbsem.h"
+#if defined(ODBC_SUPPORT)
+#include "odbccat.h"
+#endif // ODBC_SUPPORT
+#if defined(MYSQL_SUPPORT)
+#include "xtable.h"
+#include "tabmysql.h"
+#endif // MYSQL_SUPPORT
+#include "filamdbf.h"
+#include "tabxcl.h"
+#include "tabfmt.h"
+#include "reldef.h"
+#include "tabcol.h"
+#include "xindex.h"
+#if defined(WIN32)
+#include <io.h>
+#include "tabwmi.h"
+#endif // WIN32
+#include "connect.h"
+#include "user_connect.h"
+#include "ha_connect.h"
+#include "mycat.h"
+#include "myutil.h"
+#include "preparse.h"
+#include "inihandl.h"
+#if defined(LIBXML2_SUPPORT)
+#include "libdoc.h"
+#endif // LIBXML2_SUPPORT
+#include "taboccur.h"
+#include "tabpivot.h"
+
+#define my_strupr(p) my_caseup_str(default_charset_info, (p));
+#define my_strlwr(p) my_casedn_str(default_charset_info, (p));
+#define my_stricmp(a,b) my_strcasecmp(default_charset_info, (a), (b))
+
+
+/***********************************************************************/
+/* Initialize the ha_connect static members. */
+/***********************************************************************/
+#define SZCONV 8192
+#define SZWORK 67108864 // Default work area size 64M
+#define SZWMIN 4194304 // Minimum work area size 4M
+
+extern "C" {
+ char version[]= "Version 1.02.0002 March 16, 2014";
+
+#if defined(XMSG)
+ char msglang[]; // Default message language
+#endif
+ int trace= 0; // The general trace value
+ int xconv= 0; // The type conversion option
+ int zconv= SZCONV; // The text conversion size
+} // extern "C"
+
+#if defined(XMAP)
+ bool xmap= false;
+#endif // XMAP
+
+ uint worksize= SZWORK;
+ulong ha_connect::num= 0;
+//int DTVAL::Shift= 0;
+
+/* CONNECT system variables */
+static int xtrace= 0;
+static int conv_size= SZCONV;
+static uint work_size= SZWORK;
+static ulong type_conv= 0;
+#if defined(XMAP)
+static my_bool indx_map= 0;
+#endif // XMAP
+
+/***********************************************************************/
+/* Utility functions. */
+/***********************************************************************/
+PQRYRES OEMColumns(PGLOBAL g, PTOS topt, char *tab, char *db, bool info);
+void PushWarning(PGLOBAL g, THD *thd, int level);
+
+static PCONNECT GetUser(THD *thd, PCONNECT xp);
+static PGLOBAL GetPlug(THD *thd, PCONNECT& lxp);
+
+static handler *connect_create_handler(handlerton *hton,
+ TABLE_SHARE *table,
+ MEM_ROOT *mem_root);
+
+static int connect_assisted_discovery(handlerton *hton, THD* thd,
+ TABLE_SHARE *table_s,
+ HA_CREATE_INFO *info);
+
+static void update_connect_xtrace(MYSQL_THD thd,
+ struct st_mysql_sys_var *var,
+ void *var_ptr, const void *save)
+{
+ xtrace= *(int *)var_ptr= *(int *)save;
+} // end of update_connect_xtrace
+
+static void update_connect_zconv(MYSQL_THD thd,
+ struct st_mysql_sys_var *var,
+ void *var_ptr, const void *save)
+{
+ zconv= *(int *)var_ptr= *(int *)save;
+} // end of update_connect_zconv
+
+static void update_connect_xconv(MYSQL_THD thd,
+ struct st_mysql_sys_var *var,
+ void *var_ptr, const void *save)
+{
+ xconv= (int)(*(ulong *)var_ptr= *(ulong *)save);
+} // end of update_connect_xconv
+
+static void update_connect_worksize(MYSQL_THD thd,
+ struct st_mysql_sys_var *var,
+ void *var_ptr, const void *save)
+{
+ worksize= (uint)(*(ulong *)var_ptr= *(ulong *)save);
+} // end of update_connect_worksize
+
+#if defined(XMAP)
+static void update_connect_xmap(MYSQL_THD thd,
+ struct st_mysql_sys_var *var,
+ void *var_ptr, const void *save)
+{
+ xmap= (bool)(*(my_bool *)var_ptr= *(my_bool *)save);
+} // end of update_connect_xmap
+#endif // XMAP
+
+/***********************************************************************/
+/* The CONNECT handlerton object. */
+/***********************************************************************/
+handlerton *connect_hton;
+
+/**
+ CREATE TABLE option list (table options)
+
+ These can be specified in the CREATE TABLE:
+ CREATE TABLE ( ... ) {...here...}
+*/
+ha_create_table_option connect_table_option_list[]=
+{
+ HA_TOPTION_STRING("TABLE_TYPE", type),
+ HA_TOPTION_STRING("FILE_NAME", filename),
+ HA_TOPTION_STRING("XFILE_NAME", optname),
+//HA_TOPTION_STRING("CONNECT_STRING", connect),
+ HA_TOPTION_STRING("TABNAME", tabname),
+ HA_TOPTION_STRING("TABLE_LIST", tablist),
+ HA_TOPTION_STRING("DBNAME", dbname),
+ HA_TOPTION_STRING("SEP_CHAR", separator),
+ HA_TOPTION_STRING("QCHAR", qchar),
+ HA_TOPTION_STRING("MODULE", module),
+ HA_TOPTION_STRING("SUBTYPE", subtype),
+ HA_TOPTION_STRING("CATFUNC", catfunc),
+ HA_TOPTION_STRING("SRCDEF", srcdef),
+ HA_TOPTION_STRING("COLIST", colist),
+ HA_TOPTION_STRING("OPTION_LIST", oplist),
+ HA_TOPTION_STRING("DATA_CHARSET", data_charset),
+ HA_TOPTION_NUMBER("LRECL", lrecl, 0, 0, INT_MAX32, 1),
+ HA_TOPTION_NUMBER("BLOCK_SIZE", elements, 0, 0, INT_MAX32, 1),
+//HA_TOPTION_NUMBER("ESTIMATE", estimate, 0, 0, INT_MAX32, 1),
+ HA_TOPTION_NUMBER("MULTIPLE", multiple, 0, 0, 2, 1),
+ HA_TOPTION_NUMBER("HEADER", header, 0, 0, 3, 1),
+ HA_TOPTION_NUMBER("QUOTED", quoted, (ulonglong) -1, 0, 3, 1),
+ HA_TOPTION_NUMBER("ENDING", ending, (ulonglong) -1, 0, INT_MAX32, 1),
+ HA_TOPTION_NUMBER("COMPRESS", compressed, 0, 0, 2, 1),
+//HA_TOPTION_BOOL("COMPRESS", compressed, 0),
+ HA_TOPTION_BOOL("MAPPED", mapped, 0),
+ HA_TOPTION_BOOL("HUGE", huge, 0),
+ HA_TOPTION_BOOL("SPLIT", split, 0),
+ HA_TOPTION_BOOL("READONLY", readonly, 0),
+ HA_TOPTION_BOOL("SEPINDEX", sepindex, 0),
+ HA_TOPTION_END
+};
+
+
+/**
+ CREATE TABLE option list (field options)
+
+ These can be specified in the CREATE TABLE per field:
+ CREATE TABLE ( field ... {...here...}, ... )
+*/
+ha_create_table_option connect_field_option_list[]=
+{
+ HA_FOPTION_NUMBER("FLAG", offset, (ulonglong) -1, 0, INT_MAX32, 1),
+ HA_FOPTION_NUMBER("MAX_DIST", freq, 0, 0, INT_MAX32, 1), // BLK_INDX
+ HA_FOPTION_NUMBER("DISTRIB", opt, 0, 0, 2, 1), // used for BLK_INDX
+ HA_FOPTION_NUMBER("FIELD_LENGTH", fldlen, 0, 0, INT_MAX32, 1),
+ HA_FOPTION_STRING("DATE_FORMAT", dateformat),
+ HA_FOPTION_STRING("FIELD_FORMAT", fieldformat),
+ HA_FOPTION_STRING("SPECIAL", special),
+ HA_FOPTION_END
+};
+
/*
- CREATE TABLE option list (index options)
+ CREATE TABLE option list (index options)
These can be specified in the CREATE TABLE per index:
CREATE TABLE ( field ..., .., INDEX .... *here*, ... )
*/
-ha_create_table_option connect_index_option_list[]=
-{
- HA_IOPTION_BOOL("DYN", kindx, 0),
- HA_IOPTION_BOOL("MAPPED", mapped, 0),
-};
-
-/***********************************************************************/
-/* Push G->Message as a MySQL warning. */
-/***********************************************************************/
-bool PushWarning(PGLOBAL g, PTDBASE tdbp, int level)
- {
- PHC phc;
- THD *thd;
- MYCAT *cat= (MYCAT*)tdbp->GetDef()->GetCat();
- Sql_condition::enum_warning_level wlvl;
-
-
- if (!cat || !(phc= cat->GetHandler()) || !phc->GetTable() ||
- !(thd= (phc->GetTable())->in_use))
- return true;
-
-//push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
- wlvl= (Sql_condition::enum_warning_level)level;
- push_warning(thd, wlvl, 0, g->Message);
- return false;
- } // end of PushWarning
-
-#ifdef HAVE_PSI_INTERFACE
-static PSI_mutex_key con_key_mutex_CONNECT_SHARE_mutex;
-
-static PSI_mutex_info all_connect_mutexes[]=
-{
- { &con_key_mutex_CONNECT_SHARE_mutex, "CONNECT_SHARE::mutex", 0}
-};
-
-static void init_connect_psi_keys()
-{
- const char* category= "connect";
- int count;
-
- if (PSI_server == NULL)
- return;
-
- count= array_elements(all_connect_mutexes);
- PSI_server->register_mutex(category, all_connect_mutexes, count);
-}
-#else
-static void init_connect_psi_keys() {}
-#endif
-
-
-DllExport LPCSTR PlugSetPath(LPSTR to, LPCSTR name, LPCSTR dir)
-{
- const char *res= PlugSetPath(to, mysql_data_home, name, dir);
- return res;
-}
-
-
-/**
- @brief
- If frm_error() is called then we will use this to determine
- the file extensions that exist for the storage engine. This is also
- used by the default rename_table and delete_table method in
- handler.cc.
-
- For engines that have two file name extentions (separate meta/index file
- and data file), the order of elements is relevant. First element of engine
- file name extentions array should be meta/index file extention. Second
- element - data file extention. This order is assumed by
- prepare_for_repair() when REPAIR TABLE ... USE_FRM is issued.
-
- @see
- rename_table method in handler.cc and
- delete_table method in handler.cc
-*/
-static const char *ha_connect_exts[]= {
- ".dos", ".fix", ".csv", ".bin", ".fmt", ".dbf", ".xml", ".ini", ".vec",
- ".dnx", ".fnx", ".bnx", ".vnx", ".dbx", ".dop", ".fop", ".bop", ".vop",
- NULL};
-
-/**
- @brief
- Plugin initialization
-*/
-static int connect_init_func(void *p)
-{
- DBUG_ENTER("connect_init_func");
-
- sql_print_information("CONNECT: %s", version);
-
- // xtrace is now a system variable
- trace= xtrace;
-
-#ifdef LIBXML2_SUPPORT
- XmlInitParserLib();
-#endif // LIBXML2_SUPPORT
-
- init_connect_psi_keys();
-
- connect_hton= (handlerton *)p;
- connect_hton->state= SHOW_OPTION_YES;
- connect_hton->create= connect_create_handler;
- connect_hton->flags= HTON_TEMPORARY_NOT_SUPPORTED | HTON_NO_PARTITION;
- connect_hton->table_options= connect_table_option_list;
- connect_hton->field_options= connect_field_option_list;
- connect_hton->tablefile_extensions= ha_connect_exts;
- connect_hton->discover_table_structure= connect_assisted_discovery;
-
- if (xtrace)
- sql_print_information("connect_init: hton=%p", p);
-
- DTVAL::SetTimeShift(); // Initialize time zone shift once for all
- DBUG_RETURN(0);
-}
-
-
-/**
- @brief
- Plugin clean up
-*/
-static int connect_done_func(void *p)
-{
- int error= 0;
- PCONNECT pc, pn;
- DBUG_ENTER("connect_done_func");
-
-#ifdef LIBXML2_SUPPORT
- XmlCleanupParserLib();
-#endif // LIBXML2_SUPPORT
-
-#if !defined(WIN32)
-//PROFILE_End(); Causes signal 11
-#endif // !WIN32
-
- for (pc= user_connect::to_users; pc; pc= pn) {
- if (pc->g)
- PlugCleanup(pc->g, true);
-
- pn= pc->next;
- delete pc;
- } // endfor pc
-
- DBUG_RETURN(error);
-}
-
-
-/**
- @brief
- Example of simple lock controls. The "share" it creates is a
- structure we will pass to each example handler. Do you have to have
- one of these? Well, you have pieces that are used for locking, and
- they are needed to function.
-*/
-
-CONNECT_SHARE *ha_connect::get_share()
-{
- CONNECT_SHARE *tmp_share;
- lock_shared_ha_data();
- if (!(tmp_share= static_cast<CONNECT_SHARE*>(get_ha_share_ptr())))
- {
- tmp_share= new CONNECT_SHARE;
- if (!tmp_share)
- goto err;
- mysql_mutex_init(con_key_mutex_CONNECT_SHARE_mutex,
- &tmp_share->mutex, MY_MUTEX_INIT_FAST);
- set_ha_share_ptr(static_cast<Handler_share*>(tmp_share));
- }
-err:
- unlock_shared_ha_data();
- return tmp_share;
-}
-
-
-static handler* connect_create_handler(handlerton *hton,
- TABLE_SHARE *table,
- MEM_ROOT *mem_root)
-{
- handler *h= new (mem_root) ha_connect(hton, table);
-
- if (xtrace)
- htrc("New CONNECT %p, table: %s\n",
- h, table ? table->table_name.str : "<null>");
-
- return h;
-} // end of connect_create_handler
-
-/****************************************************************************/
-/* ha_connect constructor. */
-/****************************************************************************/
-ha_connect::ha_connect(handlerton *hton, TABLE_SHARE *table_arg)
- :handler(hton, table_arg)
-{
- hnum= ++num;
- xp= (table) ? GetUser(ha_thd(), NULL) : NULL;
- if (xp)
- xp->SetHandler(this);
- tdbp= NULL;
- sdvalin= NULL;
- sdvalout= NULL;
- xmod= MODE_ANY;
- istable= false;
-//*tname= '\0';
- bzero((char*) &xinfo, sizeof(XINFO));
- valid_info= false;
- valid_query_id= 0;
- creat_query_id= (table && table->in_use) ? table->in_use->query_id : 0;
- stop= false;
- alter= false;
- mrr= false;
- indexing= -1;
- locked= 0;
- data_file_name= NULL;
- index_file_name= NULL;
- enable_activate_all_index= 0;
- int_table_flags= (HA_NO_TRANSACTIONS | HA_NO_PREFIX_CHAR_KEYS);
- ref_length= sizeof(int);
- share= NULL;
- tshp= NULL;
-} // end of ha_connect constructor
-
-
-/****************************************************************************/
-/* ha_connect destructor. */
-/****************************************************************************/
-ha_connect::~ha_connect(void)
-{
- if (xtrace)
- htrc("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;
-
- xp->count--;
-
- for (p= user_connect::to_users; p; p= p->next)
- if (p == xp)
- break;
-
- if (p && !p->count) {
- if (p->next)
- p->next->previous= p->previous;
-
- if (p->previous)
- p->previous->next= p->next;
- else
- user_connect::to_users= p->next;
-
- } // endif p
-
- if (!xp->count) {
- PlugCleanup(xp->g, true);
- delete xp;
- } // endif count
-
- } // endif xp
-
-} // end of ha_connect destructor
-
-
-/****************************************************************************/
-/* Get a pointer to the user of this handler. */
-/****************************************************************************/
-static PCONNECT GetUser(THD *thd, PCONNECT xp)
-{
- const char *dbn= NULL;
-
- if (!thd)
- return NULL;
-
- if (xp && thd == xp->thdp)
- return xp;
-
- for (xp= user_connect::to_users; xp; xp= xp->next)
- if (thd == xp->thdp)
- break;
-
- if (!xp) {
- xp= new user_connect(thd, dbn);
-
- if (xp->user_init()) {
- delete xp;
- xp= NULL;
- } // endif user_init
-
- } else
- xp->count++;
-
- return xp;
-} // end of GetUser
-
-
-/****************************************************************************/
-/* Get the global pointer of the user of this handler. */
-/****************************************************************************/
-static PGLOBAL GetPlug(THD *thd, PCONNECT& lxp)
-{
- lxp= GetUser(thd, 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_CAN_VIRTUAL_COLUMNS | HA_REC_NOT_IN_SEQ |
- HA_NO_AUTO_INCREMENT | HA_NO_PREFIX_CHAR_KEYS |
- HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE |
- HA_PARTIAL_COLUMN_READ |
-// HA_NULL_IN_KEY | not implemented yet
-// HA_FAST_KEY_READ | causes error when sorting (???)
- HA_NO_TRANSACTIONS | HA_DUPLICATE_KEY_NOT_IN_ORDER |
- HA_NO_BLOBS | 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;
-
- if (IsExactType(type))
- flags|= (HA_HAS_RECORDS | HA_STATS_RECORDS_IS_EXACT);
-
- // 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. */
-/****************************************************************************/
-char *GetListOption(PGLOBAL g, const char *opname,
- const char *oplist, const char *def)
-{
- char key[16], val[256];
- char *pk, *pv, *pn;
- char *opval= (char*) def;
- int n;
-
- for (pk= (char*)oplist; pk; pk= ++pn) {
- pn= strchr(pk, ',');
- pv= strchr(pk, '=');
-
- if (pv && (!pn || pv < pn)) {
- n= pv - pk;
- memcpy(key, pk, n);
- key[n]= 0;
- pv++;
-
- if (pn) {
- n= pn - pv;
- memcpy(val, pv, n);
- val[n]= 0;
- } else
- strcpy(val, pv);
-
- } else {
- if (pn) {
- n= min(pn - pk, 15);
- memcpy(key, pk, n);
- key[n]= 0;
- } else
- strcpy(key, pk);
-
- val[0]= 0;
- } // endif pv
-
- if (!stricmp(opname, key)) {
- opval= (char*)PlugSubAlloc(g, NULL, strlen(val) + 1);
- strcpy(opval, val);
- break;
- } else if (!pn)
- break;
-
- } // endfor pk
-
- return opval;
-} // end of GetListOption
-
-/****************************************************************************/
-/* Return the table option structure. */
-/****************************************************************************/
-PTOS ha_connect::GetTableOptionStruct(TABLE *tab)
-{
- return (tshp) ? tshp->option_struct :
- (tab) ? tab->s->option_struct : NULL;
-} // end of GetTableOptionStruct
-
-/****************************************************************************/
-/* Return the value of a string option or NULL if not specified. */
-/****************************************************************************/
-char *ha_connect::GetStringOption(char *opname, char *sdef)
-{
- char *opval= NULL;
- PTOS options= GetTableOptionStruct(table);
-
- if (!options)
- ;
- else if (!stricmp(opname, "Type"))
- opval= (char*)options->type;
- else if (!stricmp(opname, "Filename"))
- opval= (char*)options->filename;
- else if (!stricmp(opname, "Optname"))
- opval= (char*)options->optname;
- else if (!stricmp(opname, "Tabname"))
- opval= (char*)options->tabname;
- else if (!stricmp(opname, "Tablist"))
- opval= (char*)options->tablist;
- else if (!stricmp(opname, "Database") ||
- !stricmp(opname, "DBname"))
- opval= (char*)options->dbname;
- else if (!stricmp(opname, "Separator"))
- opval= (char*)options->separator;
- else if (!stricmp(opname, "Connect"))
- opval= (tshp) ? tshp->connect_string.str : table->s->connect_string.str;
- else if (!stricmp(opname, "Qchar"))
- opval= (char*)options->qchar;
- else if (!stricmp(opname, "Module"))
- opval= (char*)options->module;
- else if (!stricmp(opname, "Subtype"))
- opval= (char*)options->subtype;
- else if (!stricmp(opname, "Catfunc"))
- opval= (char*)options->catfunc;
- else if (!stricmp(opname, "Srcdef"))
- opval= (char*)options->srcdef;
- else if (!stricmp(opname, "Colist"))
- opval= (char*)options->colist;
- else if (!stricmp(opname, "Data_charset"))
- opval= (char*)options->data_charset;
- else if (!stricmp(opname, "Query_String"))
- opval= thd_query_string(table->in_use)->str;
-
- if (!opval && options && options->oplist)
- opval= GetListOption(xp->g, opname, options->oplist);
-
- if (!opval) {
- if (sdef && !strcmp(sdef, "*")) {
- // Return the handler default value
- if (!stricmp(opname, "Dbname") || !stricmp(opname, "Database"))
- opval= (char*)GetDBName(NULL); // Current database
- else if (!stricmp(opname, "Type")) // Default type
- opval= (!options) ? NULL :
- (options->srcdef) ? (char*)"MYSQL" :
- (options->tabname) ? (char*)"PROXY" : (char*)"DOS";
- else if (!stricmp(opname, "User")) // Connected user
- opval= (char *) "root";
- else if (!stricmp(opname, "Host")) // Connected user host
- opval= (char *) "localhost";
- else
- opval= sdef; // Caller default
-
- } else
- opval= sdef; // Caller default
-
- } // endif !opval
-
- return opval;
-} // end of GetStringOption
-
-/****************************************************************************/
-/* Return the value of a Boolean option or bdef if not specified. */
-/****************************************************************************/
-bool ha_connect::GetBooleanOption(char *opname, bool bdef)
-{
- bool opval= bdef;
- char *pv;
- PTOS options= GetTableOptionStruct(table);
-
- if (!stricmp(opname, "View"))
- opval= (tshp) ? tshp->is_view : table->s->is_view;
- else if (!options)
- ;
- else if (!stricmp(opname, "Mapped"))
- opval= options->mapped;
- else if (!stricmp(opname, "Huge"))
- opval= options->huge;
-//else if (!stricmp(opname, "Compressed"))
-// opval= options->compressed;
- else if (!stricmp(opname, "Split"))
- opval= options->split;
- else if (!stricmp(opname, "Readonly"))
- opval= options->readonly;
- else if (!stricmp(opname, "SepIndex"))
- opval= options->sepindex;
- else if (options->oplist)
- if ((pv= GetListOption(xp->g, opname, options->oplist)))
- opval= (!*pv || *pv == 'y' || *pv == 'Y' || atoi(pv) != 0);
-
- return opval;
-} // end of GetBooleanOption
-
-/****************************************************************************/
-/* Set the value of the opname option (does not work for oplist options) */
-/* Currently used only to set the Sepindex value. */
-/****************************************************************************/
-bool ha_connect::SetBooleanOption(char *opname, bool b)
-{
- PTOS options= GetTableOptionStruct(table);
-
- if (!options)
- return true;
-
- if (!stricmp(opname, "SepIndex"))
- options->sepindex= b;
- else
- return true;
-
- return false;
-} // end of SetBooleanOption
-
-/****************************************************************************/
-/* Return the value of an integer option or NO_IVAL if not specified. */
-/****************************************************************************/
-int ha_connect::GetIntegerOption(char *opname)
-{
- ulonglong opval= NO_IVAL;
- char *pv;
- PTOS options= GetTableOptionStruct(table);
-
- if (!options)
- ;
- else if (!stricmp(opname, "Lrecl"))
- opval= options->lrecl;
- else if (!stricmp(opname, "Elements"))
- opval= options->elements;
- else if (!stricmp(opname, "Estimate"))
-// opval= options->estimate;
- opval= (int)table->s->max_rows;
- else if (!stricmp(opname, "Avglen"))
- opval= (int)table->s->avg_row_length;
- else if (!stricmp(opname, "Multiple"))
- opval= options->multiple;
- else if (!stricmp(opname, "Header"))
- opval= options->header;
- else if (!stricmp(opname, "Quoted"))
- opval= options->quoted;
- else if (!stricmp(opname, "Ending"))
- opval= options->ending;
- else if (!stricmp(opname, "Compressed"))
- opval= (options->compressed);
-
- if (opval == (ulonglong)NO_IVAL && options && options->oplist)
- if ((pv= GetListOption(xp->g, opname, options->oplist)))
- opval= CharToNumber(pv, strlen(pv), ULONGLONG_MAX, true);
-
- return (int)opval;
-} // end of GetIntegerOption
-
-/****************************************************************************/
-/* Set the value of the opname option (does not work for oplist options) */
-/* Currently used only to set the Lrecl value. */
-/****************************************************************************/
-bool ha_connect::SetIntegerOption(char *opname, int n)
-{
- PTOS options= GetTableOptionStruct(table);
-
- if (!options)
- return true;
-
- if (!stricmp(opname, "Lrecl"))
- options->lrecl= n;
- else if (!stricmp(opname, "Elements"))
- options->elements= n;
-//else if (!stricmp(opname, "Estimate"))
-// options->estimate= n;
- else if (!stricmp(opname, "Multiple"))
- options->multiple= n;
- else if (!stricmp(opname, "Header"))
- options->header= n;
- else if (!stricmp(opname, "Quoted"))
- options->quoted= n;
- else if (!stricmp(opname, "Ending"))
- options->ending= n;
- else if (!stricmp(opname, "Compressed"))
- options->compressed= n;
- else
- return true;
-//else if (options->oplist)
-// SetListOption(opname, options->oplist, n);
-
- return false;
-} // end of SetIntegerOption
-
-/****************************************************************************/
-/* Return a field option structure. */
-/****************************************************************************/
-PFOS ha_connect::GetFieldOptionStruct(Field *fdp)
-{
- return fdp->option_struct;
-} // end of GetFildOptionStruct
-
-/****************************************************************************/
-/* Returns the column description structure used to make the column. */
-/****************************************************************************/
-void *ha_connect::GetColumnOption(PGLOBAL g, void *field, PCOLINFO pcf)
-{
- const char *cp;
- ha_field_option_struct *fop;
- Field* fp;
- Field* *fldp;
-
- // Double test to be on the safe side
- if (!table)
- return NULL;
-
- // Find the column to describe
- if (field) {
- fldp= (Field**)field;
- fldp++;
- } else
- fldp= (tshp) ? tshp->field : table->field;
-
- if (!fldp || !(fp= *fldp))
- return NULL;
-
- // Get the CONNECT field options structure
- fop= GetFieldOptionStruct(fp);
- pcf->Flags= 0;
-
- // Now get column information
- pcf->Name= (char*)fp->field_name;
-
- if (fop && fop->special) {
- pcf->Fieldfmt= (char*)fop->special;
- pcf->Flags= U_SPECIAL;
- return fldp;
- } // endif special
-
- pcf->Scale= 0;
- pcf->Opt= (fop) ? (int)fop->opt : 0;
-
- if ((pcf->Length= fp->field_length) < 0)
- pcf->Length= 256; // BLOB?
-
- pcf->Precision= pcf->Length;
-
- if (fop) {
- pcf->Offset= (int)fop->offset;
- pcf->Freq= (int)fop->freq;
- pcf->Datefmt= (char*)fop->dateformat;
- pcf->Fieldfmt= (char*)fop->fieldformat;
- } else {
- pcf->Offset= -1;
- pcf->Freq= 0;
- pcf->Datefmt= NULL;
- pcf->Fieldfmt= NULL;
- } // endif fop
-
- switch (fp->type()) {
- case MYSQL_TYPE_BLOB:
- case MYSQL_TYPE_VARCHAR:
- case MYSQL_TYPE_VAR_STRING:
- pcf->Flags |= U_VAR;
- /* no break */
- default:
- pcf->Type= MYSQLtoPLG(fp->type());
- break;
- } // endswitch SQL type
-
- switch (pcf->Type) {
- case TYPE_STRING:
- // Do something for case
- cp= fp->charset()->name;
-
- // Find if collation name ends by _ci
- if (!strcmp(cp + strlen(cp) - 3, "_ci")) {
- pcf->Scale= 1; // Case insensitive
- pcf->Opt= 0; // Prevent index opt until it is safe
- } // endif ci
-
- break;
- case TYPE_DOUBLE:
- pcf->Scale= max(min(fp->decimals(), ((unsigned)pcf->Length - 2)), 0);
- break;
- case TYPE_DECIM:
- pcf->Precision= ((Field_new_decimal*)fp)->precision;
- pcf->Scale= fp->decimals();
- break;
- case TYPE_DATE:
- // Field_length is only used for DATE columns
- if (fop && fop->fldlen)
- pcf->Length= (int)fop->fldlen;
- else {
- int len;
-
- if (pcf->Datefmt) {
- // Find the (max) length produced by the date format
- char buf[256];
- PGLOBAL g= GetPlug(table->in_use, xp);
- PDTP pdtp= MakeDateFormat(g, pcf->Datefmt, false, true, 0);
- struct tm datm;
- bzero(&datm, sizeof(datm));
- datm.tm_mday= 12;
- datm.tm_mon= 11;
- datm.tm_year= 112;
- len= strftime(buf, 256, pdtp->OutFmt, &datm);
- } else
- len= 0;
-
- // 11 is for signed numeric representation of the date
- pcf->Length= (len) ? len : 11;
- } // endelse
-
- break;
- default:
- break;
- } // endswitch type
-
- if (fp->flags & UNSIGNED_FLAG)
- pcf->Flags |= U_UNSIGNED;
-
- if (fp->flags & ZEROFILL_FLAG)
- pcf->Flags |= U_ZEROFILL;
-
- // This is used to skip null bit
- if (fp->real_maybe_null())
- pcf->Flags |= U_NULLS;
-
- // Mark virtual columns as such
- if (fp->vcol_info && !fp->stored_in_db)
- pcf->Flags |= U_VIRTUAL;
-
- pcf->Key= 0; // Not used when called from MySQL
-
- // Get the comment if any
- 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;
- } else
- pcf->Remark= NULL;
-
- return fldp;
-} // end of GetColumnOption
-
-/****************************************************************************/
-/* Returns the index description structure used to make the index. */
-/****************************************************************************/
-PIXDEF ha_connect::GetIndexInfo(TABLE_SHARE *s)
-{
- char *name, *pn;
- bool unique;
- PIXDEF xdp, pxd=NULL, toidx= NULL;
- PKPDEF kpp, pkp;
- KEY kp;
- PGLOBAL& g= xp->g;
-
- if (!s)
- s= table->s;
-
- for (int n= 0; (unsigned)n < s->keynames.count; n++) {
- if (xtrace)
- htrc("Getting created index %d info\n", n + 1);
-
- // Find the index to describe
- kp= s->key_info[n];
-
- // Now get index information
- 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;
- pkp= NULL;
-
- // Allocate the index description block
- xdp= new(g) INDEXDEF(name, unique, n);
-
- // Get the the key parts info
- for (int k= 0; (unsigned)k < kp.user_defined_key_parts; k++) {
- pn= (char*)kp.key_part[k].field->field_name;
- name= (char*)PlugSubAlloc(g, NULL, strlen(pn) + 1);
- strcpy(name, pn); // This is probably unuseful
-
- // Allocate the key part description block
- kpp= new(g) KPARTDEF(name, k + 1);
- kpp->SetKlen(kp.key_part[k].length);
-
-#if 0 // NIY
- // Index on auto increment column can be an XXROW index
- if (kp.key_part[k].field->flags & AUTO_INCREMENT_FLAG &&
- kp.uder_defined_key_parts == 1) {
- char *type= GetStringOption("Type", "DOS");
- TABTYPE typ= GetTypeID(type);
-
- xdp->SetAuto(IsTypeFixed(typ));
- } // endif AUTO_INCREMENT
-#endif // 0
-
- if (pkp)
- pkp->SetNext(kpp);
- else
- xdp->SetToKeyParts(kpp);
-
- pkp= kpp;
- } // endfor k
-
- xdp->SetNParts(kp.user_defined_key_parts);
-
- if (pxd)
- pxd->SetNext(xdp);
- else
- toidx= xdp;
-
- pxd= xdp;
- } // endfor n
-
- return toidx;
-} // end of GetIndexInfo
-
-const char *ha_connect::GetDBName(const char* name)
-{
- return (name) ? name : table->s->db.str;
-} // end of GetDBName
-
-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. */
-/****************************************************************************/
-int ha_connect::GetColNameLen(Field *fp)
-{
- int n;
- PFOS fop= GetFieldOptionStruct(fp);
-
- // Now get the column name length
- if (fop && fop->special)
- n= strlen(fop->special) + 1;
- else
- n= strlen(fp->field_name);
-
- return n;
-} // end of GetColNameLen
-
-/****************************************************************************/
-/* Returns the column real or special name of a field. */
-/****************************************************************************/
-char *ha_connect::GetColName(Field *fp)
-{
- PFOS fop= GetFieldOptionStruct(fp);
-
- return (fop && fop->special) ? fop->special : (char*)fp->field_name;
-} // end of GetColName
-
-/****************************************************************************/
-/* Adds the column real or special name of a field to a string. */
-/****************************************************************************/
-void ha_connect::AddColName(char *cp, Field *fp)
-{
- PFOS fop= GetFieldOptionStruct(fp);
-
- // Now add the column name
- if (fop && fop->special)
- // The prefix * mark the column as "special"
- strcat(strcpy(cp, "*"), strupr(fop->special));
- else
- strcpy(cp, (char*)fp->field_name);
-
-} // end of AddColName
-#endif // 0
-
-/****************************************************************************/
-/* Get the table description block of a CONNECT table. */
-/****************************************************************************/
-PTDB ha_connect::GetTDB(PGLOBAL g)
-{
- const char *table_name;
- PTDB tp;
-
- // Double test to be on the safe side
- if (!g || !table)
- return NULL;
-
- table_name= GetTableName();
-
- if (!xp->CheckQuery(valid_query_id) && tdbp
- && !stricmp(tdbp->GetName(), table_name)
- && (tdbp->GetMode() == xmod
- || tdbp->GetAmType() == TYPE_AM_XML)) {
- tp= tdbp;
-// tp->SetMode(xmod);
- } else if ((tp= CntGetTDB(g, table_name, xmod, this))) {
- valid_query_id= xp->last_query_id;
- tp->SetMode(xmod);
- } else
- htrc("GetTDB: %s\n", g->Message);
-
- return tp;
-} // end of GetTDB
-
-/****************************************************************************/
-/* Open a CONNECT table, restricting column list if cols is true. */
-/****************************************************************************/
-int ha_connect::OpenTable(PGLOBAL g, bool del)
-{
- bool rc= false;
- char *c1= NULL, *c2=NULL;
-
- // Double test to be on the safe side
- if (!g || !table) {
- htrc("OpenTable logical error; g=%p table=%p\n", g, table);
- return HA_ERR_INITIALIZATION;
- } // endif g
-
- if (!(tdbp= GetTDB(g)))
- return RC_FX;
- else if (tdbp->IsReadOnly())
- switch (xmod) {
- case MODE_WRITE:
- case MODE_INSERT:
- case MODE_UPDATE:
- case MODE_DELETE:
- strcpy(g->Message, MSG(READ_ONLY));
- return HA_ERR_TABLE_READONLY;
- default:
- break;
- } // endswitch xmode
-
- if (xmod != MODE_INSERT || tdbp->GetAmType() == TYPE_AM_ODBC
- || tdbp->GetAmType() == TYPE_AM_MYSQL) {
- // Get the list of used fields (columns)
- char *p;
- unsigned int k1, k2, n1, n2;
- Field* *field;
- Field* fp;
- MY_BITMAP *map= (xmod == MODE_INSERT) ? table->write_set : 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; 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, fp->field_index)) {
- n2+= (strlen(fp->field_name) + 1);
- k2++;
- } // endif
-
- } // endfor field
-
- if (k1) {
- p= c1= (char*)PlugSubAlloc(g, NULL, n1);
-
- 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
-
- *p= '\0'; // mark end of list
- } // endif k1
-
- if (k2) {
- p= c2= (char*)PlugSubAlloc(g, NULL, n2);
-
- 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
-
- *p= '\0'; // mark end of list
- } // endif k2
-
- } // endif xmod
-
- // Open the table
- if (!(rc= CntOpenTable(g, tdbp, xmod, c1, c2, del, this))) {
- istable= true;
-// strmake(tname, table_name, sizeof(tname)-1);
-
- // We may be in a create index query
- if (xmod == MODE_ANY && *tdbp->GetName() != '#') {
- // The current indexes
- PIXDEF oldpix= GetIndexInfo();
- } // endif xmod
-
- } else
- htrc("OpenTable: %s\n", g->Message);
-
- if (rc) {
- tdbp= NULL;
- valid_info= false;
- } // endif rc
-
- return (rc) ? HA_ERR_INITIALIZATION : 0;
-} // end of OpenTable
-
-
-/****************************************************************************/
-/* IsOpened: returns true if the table is already opened. */
-/****************************************************************************/
-bool ha_connect::IsOpened(void)
-{
- return (!xp->CheckQuery(valid_query_id) && tdbp
- && tdbp->GetUse() == USE_OPEN);
-} // end of IsOpened
-
-
-/****************************************************************************/
-/* Close a CONNECT table. */
-/****************************************************************************/
-int ha_connect::CloseTable(PGLOBAL g)
-{
- int rc= CntCloseTable(g, tdbp);
- tdbp= NULL;
- sdvalin=NULL;
- sdvalout=NULL;
- valid_info= false;
- indexing= -1;
- return rc;
-} // end of CloseTable
-
-
-/***********************************************************************/
-/* Make a pseudo record from current row values. Specific to MySQL. */
-/***********************************************************************/
-int ha_connect::MakeRecord(char *buf)
-{
- char *p, *fmt, val[32];
- int rc= 0;
- Field* *field;
- Field *fp;
- my_bitmap_map *org_bitmap;
- CHARSET_INFO *charset= tdbp->data_charset();
-//MY_BITMAP readmap;
- MY_BITMAP *map;
- PVAL value;
- PCOL colp= NULL;
- DBUG_ENTER("ha_connect::MakeRecord");
-
- if (xtrace > 1)
- htrc("Maps: read=%08X write=%08X vcol=%08X defr=%08X defw=%08X\n",
- *table->read_set->bitmap, *table->write_set->bitmap,
- *table->vcol_set->bitmap,
- *table->def_read_set.bitmap, *table->def_write_set.bitmap);
-
- // Avoid asserts in field::store() for columns that are not updated
- org_bitmap= dbug_tmp_use_all_columns(table, table->write_set);
-
- // This is for variable_length rows
- memset(buf, 0, table->s->null_bytes);
-
- // When sorting read_set selects all columns, so we use def_read_set
- map= (MY_BITMAP *)&table->def_read_set;
-
- // Make the pseudo record from field values
- for (field= table->field; *field && !rc; field++) {
- fp= *field;
-
- if (fp->vcol_info && !fp->stored_in_db)
- continue; // This is a virtual column
-
- 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 ((!mrr || colp->GetKcol()) &&
- !stricmp(colp->GetName(), (char*)fp->field_name))
- break;
-
- if (!colp) {
- if (mrr)
- continue;
-
- htrc("Column %s not found\n", fp->field_name);
- dbug_tmp_restore_column_map(table->write_set, org_bitmap);
- DBUG_RETURN(HA_ERR_WRONG_IN_RECORD);
- } // endif colp
-
- value= colp->GetValue();
-
- // All this could be better optimized
- if (!value->IsNull()) {
- switch (value->GetType()) {
- case TYPE_DATE:
- if (!sdvalout)
- sdvalout= AllocateValue(xp->g, TYPE_STRING, 20);
-
- switch (fp->type()) {
- case MYSQL_TYPE_DATE:
- fmt= "%Y-%m-%d";
- break;
- case MYSQL_TYPE_TIME:
- fmt= "%H:%M:%S";
- break;
- case MYSQL_TYPE_YEAR:
- fmt= "%Y";
- break;
- default:
- fmt= "%Y-%m-%d %H:%M:%S";
- break;
- } // endswitch type
-
- // Get date in the format required by MySQL fields
- value->FormatValue(sdvalout, fmt);
- p= sdvalout->GetCharValue();
- break;
- case TYPE_DOUBLE:
- p= NULL;
- break;
- case TYPE_STRING:
- // Passthru
- default:
- p= value->GetCharString(val);
- break;
- } // endswitch Type
-
- if (p) {
- if (fp->store(p, strlen(p), charset, CHECK_FIELD_WARN)) {
- // Avoid "error" on null fields
- if (value->GetIntValue())
- rc= HA_ERR_WRONG_IN_RECORD;
-
- DBUG_PRINT("MakeRecord", ("%s", p));
- } // endif store
-
- } else
- if (fp->store(value->GetFloatValue())) {
-// rc= HA_ERR_WRONG_IN_RECORD; a Warning was ignored
- char buf[128];
- THD *thd= ha_thd();
-
- sprintf(buf, "Out of range value for column '%s' at row %ld",
- fp->field_name,
- thd->get_stmt_da()->current_row_for_warning());
-
- push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, buf);
- DBUG_PRINT("MakeRecord", ("%s", value->GetCharString(val)));
- } // endif store
-
- fp->set_notnull();
- } else
- fp->set_null();
-
- } // endif bitmap
-
- } // endfor field
-
- // This is copied from ha_tina and is necessary to avoid asserts
- dbug_tmp_restore_column_map(table->write_set, org_bitmap);
- DBUG_RETURN(rc);
-} // end of MakeRecord
-
-
-/***********************************************************************/
-/* Set row values from a MySQL pseudo record. Specific to MySQL. */
-/***********************************************************************/
-int ha_connect::ScanRecord(PGLOBAL g, uchar *buf)
-{
- char attr_buffer[1024];
- char data_buffer[1024];
- char *fmt;
- int rc= 0;
- PCOL colp;
- PVAL value;
- Field *fp;
- PTDBASE tp= (PTDBASE)tdbp;
- String attribute(attr_buffer, sizeof(attr_buffer),
- table->s->table_charset);
- my_bitmap_map *bmap= dbug_tmp_use_all_columns(table, table->read_set);
- const CHARSET_INFO *charset= tdbp->data_charset();
- String data_charset_value(data_buffer, sizeof(data_buffer), charset);
-
- // Scan the pseudo record for field values and set column values
- for (Field **field=table->field ; *field ; field++) {
- fp= *field;
-
- if ((fp->vcol_info && !fp->stored_in_db) ||
- fp->option_struct->special)
- continue; // Is a virtual column possible here ???
-
- if ((xmod == MODE_INSERT && tdbp->GetAmType() != TYPE_AM_MYSQL
- && tdbp->GetAmType() != TYPE_AM_ODBC) ||
- bitmap_is_set(table->write_set, fp->field_index)) {
- for (colp= tp->GetSetCols(); colp; colp= colp->GetNext())
- if (!stricmp(colp->GetName(), fp->field_name))
- break;
-
- if (!colp) {
- htrc("Column %s not found\n", fp->field_name);
- rc= HA_ERR_WRONG_IN_RECORD;
- goto err;
- } else
- value= colp->GetValue();
-
- // This is a used field, fill the value from the row buffer
- // All this could be better optimized
- if (fp->is_null()) {
- if (colp->IsNullable())
- value->SetNull(true);
-
- value->Reset();
- } else switch (value->GetType()) {
- case TYPE_DOUBLE:
- value->SetValue(fp->val_real());
- break;
- case TYPE_DATE:
- if (!sdvalin)
- sdvalin= (DTVAL*)AllocateValue(xp->g, TYPE_DATE, 19);
-
- // Get date in the format produced by MySQL fields
- switch (fp->type()) {
- case MYSQL_TYPE_DATE:
- fmt= "YYYY-MM-DD";
- break;
- case MYSQL_TYPE_TIME:
- fmt= "hh:mm:ss";
- break;
- case MYSQL_TYPE_YEAR:
- fmt= "YYYY";
- break;
- default:
- fmt= "YYYY-MM-DD hh:mm:ss";
- } // endswitch type
-
- ((DTVAL*)sdvalin)->SetFormat(g, fmt, strlen(fmt));
- fp->val_str(&attribute);
- sdvalin->SetValue_psz(attribute.c_ptr_safe());
- value->SetValue_pval(sdvalin);
- break;
- default:
- fp->val_str(&attribute);
-
- 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
-
-#ifdef NEWCHANGE
- } else if (xmod == MODE_UPDATE) {
- PCOL cp;
-
- for (cp= tp->GetColumns(); cp; cp= cp->GetNext())
- if (!stricmp(colp->GetName(), cp->GetName()))
- break;
-
- if (!cp) {
- rc= HA_ERR_WRONG_IN_RECORD;
- goto err;
- } // endif cp
-
- value->SetValue_pval(cp->GetValue());
- } else // mode Insert
- value->Reset();
-#else
- } // endif bitmap_is_set
-#endif
-
- } // endfor field
-
- err:
- dbug_tmp_restore_column_map(table->read_set, bmap);
- return rc;
-} // end of ScanRecord
-
-
-/***********************************************************************/
-/* Check change in index column. Specific to MySQL. */
-/* Should be elaborated to check for real changes. */
-/***********************************************************************/
-int ha_connect::CheckRecord(PGLOBAL g, const uchar *oldbuf, uchar *newbuf)
-{
- return ScanRecord(g, newbuf);
-} // end of dummy CheckRecord
-
-
-/***********************************************************************/
-/* Return the string representing an operator. */
-/***********************************************************************/
-const char *ha_connect::GetValStr(OPVAL vop, bool neg)
-{
- const char *val;
-
- switch (vop) {
- case OP_EQ:
- val= " = ";
- break;
- case OP_NE:
- val= " <> ";
- break;
- case OP_GT:
- val= " > ";
- break;
- case OP_GE:
- val= " >= ";
- break;
- case OP_LT:
- val= " < ";
- break;
- case OP_LE:
- val= " <= ";
- break;
- case OP_IN:
- val= (neg) ? " NOT IN (" : " IN (";
- break;
- case OP_NULL:
- val= (neg) ? " IS NOT NULL" : " IS NULL";
- break;
- case OP_LIKE:
- val= " LIKE ";
- break;
- case OP_XX:
- val= (neg) ? " NOT BETWEEN " : " BETWEEN ";
- break;
- case OP_EXIST:
- val= (neg) ? " NOT EXISTS " : " EXISTS ";
- break;
- case OP_AND:
- val= " AND ";
- break;
- case OP_OR:
- val= " OR ";
- break;
- case OP_NOT:
- val= " NOT ";
- break;
- case OP_CNC:
- val= " || ";
- break;
- case OP_ADD:
- val= " + ";
- break;
- case OP_SUB:
- val= " - ";
- break;
- case OP_MULT:
- val= " * ";
- break;
- case OP_DIV:
- val= " / ";
- break;
- default:
- val= " ? ";
- break;
- } /* endswitch */
-
- return val;
-} // end of GetValStr
-
-
-/***********************************************************************/
-/* Check the WHERE condition and return a CONNECT filter. */
-/***********************************************************************/
-PFIL ha_connect::CondFilter(PGLOBAL g, Item *cond)
-{
- unsigned int i;
- bool ismul= false;
- OPVAL vop= OP_XX;
- PFIL filp= NULL;
-
- if (!cond)
- return NULL;
-
- if (xtrace)
- htrc("Cond type=%d\n", cond->type());
-
- if (cond->type() == COND::COND_ITEM) {
- PFIL fp;
- Item_cond *cond_item= (Item_cond *)cond;
-
- if (xtrace)
- htrc("Cond: Ftype=%d name=%s\n", cond_item->functype(),
- cond_item->func_name());
-
- switch (cond_item->functype()) {
- case Item_func::COND_AND_FUNC: vop= OP_AND; break;
- case Item_func::COND_OR_FUNC: vop= OP_OR; break;
- default: return NULL;
- } // endswitch functype
-
- List<Item>* arglist= cond_item->argument_list();
- List_iterator<Item> li(*arglist);
- Item *subitem;
-
- for (i= 0; i < arglist->elements; i++)
- if ((subitem= li++)) {
- if (!(fp= CondFilter(g, subitem))) {
- if (vop == OP_OR)
- return NULL;
- } else
- filp= (filp) ? MakeFilter(g, filp, vop, fp) : fp;
-
- } else
- return NULL;
-
- } else if (cond->type() == COND::FUNC_ITEM) {
- unsigned int i;
- bool iscol, neg= FALSE;
- PCOL colp[2]= {NULL,NULL};
- PPARM pfirst= NULL, pprec= NULL;
- POPER pop;
- Item_func *condf= (Item_func *)cond;
- Item* *args= condf->arguments();
-
- if (xtrace)
- htrc("Func type=%d argnum=%d\n", condf->functype(),
- condf->argument_count());
-
- switch (condf->functype()) {
- case Item_func::EQUAL_FUNC:
- case Item_func::EQ_FUNC: vop= OP_EQ; break;
- case Item_func::NE_FUNC: vop= OP_NE; break;
- case Item_func::LT_FUNC: vop= OP_LT; break;
- case Item_func::LE_FUNC: vop= OP_LE; break;
- case Item_func::GE_FUNC: vop= OP_GE; break;
- case Item_func::GT_FUNC: vop= OP_GT; break;
- case Item_func::IN_FUNC: vop= OP_IN;
- case Item_func::BETWEEN:
- ismul= true;
- neg= ((Item_func_opt_neg *)condf)->negated;
- break;
- default: return NULL;
- } // endswitch functype
-
- pop= (POPER)PlugSubAlloc(g, NULL, sizeof(OPER));
- pop->Name= NULL;
- pop->Val=vop;
- pop->Mod= 0;
-
- if (condf->argument_count() < 2)
- return NULL;
-
- for (i= 0; i < condf->argument_count(); i++) {
- if (xtrace)
- htrc("Argtype(%d)=%d\n", i, args[i]->type());
-
- if (i >= 2 && !ismul) {
- if (xtrace)
- htrc("Unexpected arg for vop=%d\n", vop);
-
- continue;
- } // endif i
-
- if ((iscol= args[i]->type() == COND::FIELD_ITEM)) {
- Item_field *pField= (Item_field *)args[i];
-
- // IN and BETWEEN clauses should be col VOP list
- if (i && ismul)
- return NULL;
-
- if (pField->field->table != table ||
- !(colp[i]= tdbp->ColDB(g, (PSZ)pField->field->field_name, 0)))
- return NULL; // Column does not belong to this table
-
- if (xtrace) {
- htrc("Field index=%d\n", pField->field->field_index);
- htrc("Field name=%s\n", pField->field->field_name);
- } // endif xtrace
-
- } else {
- char buff[256];
- String *res, tmp(buff, sizeof(buff), &my_charset_bin);
- Item_basic_constant *pval= (Item_basic_constant *)args[i];
- PPARM pp= (PPARM)PlugSubAlloc(g, NULL, sizeof(PARM));
-
- // IN and BETWEEN clauses should be col VOP list
- if (!i && (ismul))
- return NULL;
-
- if ((res= pval->val_str(&tmp)) == NULL)
- return NULL; // To be clarified
-
- switch (args[i]->real_type()) {
- case COND::STRING_ITEM:
- pp->Type= TYPE_STRING;
- pp->Value= PlugSubAlloc(g, NULL, res->length() + 1);
- strncpy((char*)pp->Value, res->ptr(), res->length() + 1);
- break;
- case COND::INT_ITEM:
- pp->Type= TYPE_INT;
- pp->Value= PlugSubAlloc(g, NULL, sizeof(int));
- *((int*)pp->Value)= (int)pval->val_int();
- break;
- case COND::DATE_ITEM:
- pp->Type= TYPE_DATE;
- pp->Value= PlugSubAlloc(g, NULL, sizeof(int));
- *((int*)pp->Value)= (int)pval->val_int_from_date();
- break;
- case COND::REAL_ITEM:
- pp->Type= TYPE_DOUBLE;
- pp->Value= PlugSubAlloc(g, NULL, sizeof(double));
- *((double*)pp->Value)= pval->val_real();
- break;
- case COND::DECIMAL_ITEM:
- pp->Type= TYPE_DOUBLE;
- pp->Value= PlugSubAlloc(g, NULL, sizeof(double));
- *((double*)pp->Value)= pval->val_real_from_decimal();
- break;
- case COND::CACHE_ITEM: // Possible ???
- case COND::NULL_ITEM: // TODO: handle this
- default:
- return NULL;
- } // endswitch type
-
- if (xtrace)
- htrc("Value=%.*s\n", res->length(), res->ptr());
-
- // Append the value to the argument list
- if (pprec)
- pprec->Next= pp;
- else
- pfirst= pp;
-
- pp->Domain= i;
- pp->Next= NULL;
- pprec= pp;
- } // endif type
-
- } // endfor i
-
- filp= MakeFilter(g, colp, pop, pfirst, neg);
- } else {
- if (xtrace)
- htrc("Unsupported condition\n");
-
- return NULL;
- } // endif's type
-
- return filp;
-} // end of CondFilter
-
-/***********************************************************************/
-/* Check the WHERE condition and return a MYSQL/ODBC/WQL filter. */
-/***********************************************************************/
-PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, AMT tty, Item *cond)
-{
- char *body= filp->Body;
- unsigned int i;
- bool ismul= false, x= (tty == TYPE_AM_MYX || tty == TYPE_AM_XDBC);
- OPVAL vop= OP_XX;
-
- if (!cond)
- return NULL;
-
- if (xtrace)
- htrc("Cond type=%d\n", cond->type());
-
- if (cond->type() == COND::COND_ITEM) {
- char *p1, *p2;
- Item_cond *cond_item= (Item_cond *)cond;
-
- if (x)
- return NULL;
-
- if (xtrace)
- htrc("Cond: Ftype=%d name=%s\n", cond_item->functype(),
- cond_item->func_name());
-
- switch (cond_item->functype()) {
- case Item_func::COND_AND_FUNC: vop= OP_AND; break;
- case Item_func::COND_OR_FUNC: vop= OP_OR; break;
- default: return NULL;
- } // endswitch functype
-
- List<Item>* arglist= cond_item->argument_list();
- List_iterator<Item> li(*arglist);
- Item *subitem;
-
- p1= body + strlen(body);
- strcpy(p1, "(");
- p2= p1 + 1;
-
- for (i= 0; i < arglist->elements; i++)
- if ((subitem= li++)) {
- if (!CheckCond(g, filp, tty, subitem)) {
- if (vop == OP_OR)
- return NULL;
- else
- *p2= 0;
-
- } else {
- p1= p2 + strlen(p2);
- strcpy(p1, GetValStr(vop, FALSE));
- p2= p1 + strlen(p1);
- } // endif CheckCond
-
- } else
- return NULL;
-
- if (*p1 != '(')
- strcpy(p1, ")");
- else
- return NULL;
-
- } else if (cond->type() == COND::FUNC_ITEM) {
- unsigned int i;
-// int n;
- bool iscol, neg= FALSE;
- Item_func *condf= (Item_func *)cond;
- Item* *args= condf->arguments();
-
- if (xtrace)
- htrc("Func type=%d argnum=%d\n", condf->functype(),
- condf->argument_count());
-
-// neg= condf->
-
- switch (condf->functype()) {
- case Item_func::EQUAL_FUNC:
- case Item_func::EQ_FUNC: vop= OP_EQ; break;
- case Item_func::NE_FUNC: vop= OP_NE; break;
- case Item_func::LT_FUNC: vop= OP_LT; break;
- case Item_func::LE_FUNC: vop= OP_LE; break;
- case Item_func::GE_FUNC: vop= OP_GE; break;
- case Item_func::GT_FUNC: vop= OP_GT; break;
- case Item_func::IN_FUNC: vop= OP_IN;
- case Item_func::BETWEEN:
- ismul= true;
- neg= ((Item_func_opt_neg *)condf)->negated;
- break;
- default: return NULL;
- } // endswitch functype
-
- if (condf->argument_count() < 2)
- return NULL;
- else if (ismul && tty == TYPE_AM_WMI)
- return NULL; // Not supported by WQL
-
- if (x && (neg || !(vop == OP_EQ || vop == OP_IN)))
- return NULL;
-
- for (i= 0; i < condf->argument_count(); i++) {
- if (xtrace)
- htrc("Argtype(%d)=%d\n", i, args[i]->type());
-
- if (i >= 2 && !ismul) {
- if (xtrace)
- htrc("Unexpected arg for vop=%d\n", vop);
-
- continue;
- } // endif i
-
- if ((iscol= args[i]->type() == COND::FIELD_ITEM)) {
- const char *fnm;
- ha_field_option_struct *fop;
- Item_field *pField= (Item_field *)args[i];
-
- if (x && i)
- return NULL;
-
- if (pField->field->table != table)
- return NULL; // Field does not belong to this table
- else
- fop= GetFieldOptionStruct(pField->field);
-
- 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;
-
- } else if (tty == TYPE_AM_TBL)
- return NULL;
- else
- fnm= pField->field->field_name;
-
- if (xtrace) {
- htrc("Field index=%d\n", pField->field->field_index);
- htrc("Field name=%s\n", pField->field->field_name);
- } // endif xtrace
-
- // IN and BETWEEN clauses should be col VOP list
- if (i && ismul)
- 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]->real_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)
- htrc("Value=%.*s\n", res->length(), res->ptr());
-
- // IN and BETWEEN clauses should be col VOP list
- if (!i && (x || ismul))
- return NULL;
-
- if (!x) {
- // Append the value to the filter
- if (args[i]->field_type() == MYSQL_TYPE_VARCHAR)
- strcat(strcat(strcat(body, "'"), res->ptr()), "'");
- else
- strncat(body, res->ptr(), res->length());
-
- } else {
- if (args[i]->field_type() == MYSQL_TYPE_VARCHAR) {
- // Add the command to the list
- PCMD *ncp, cmdp= new(g) CMD(g, (char*)res->ptr());
-
- for (ncp= &filp->Cmds; *ncp; ncp= &(*ncp)->Next) ;
-
- *ncp= cmdp;
- } else
- return NULL;
-
- } // endif x
-
- } // endif
-
- if (!x) {
- if (!i)
- strcat(body, GetValStr(vop, neg));
- else if (vop == OP_XX && i == 1)
- strcat(body, " AND ");
- else if (vop == OP_IN)
- strcat(body, (i == condf->argument_count() - 1) ? ")" : ",");
-
- } // endif x
-
- } // endfor i
-
- if (x)
- filp->Op= vop;
-
- } else {
- if (xtrace)
- htrc("Unsupported condition\n");
-
- return NULL;
- } // endif's type
-
- return filp;
-} // end of CheckCond
-
-
- /**
- Push condition down to the table handler.
-
- @param cond Condition to be pushed. The condition tree must not be
- modified by the caller.
-
- @return
- The 'remainder' condition that caller must use to filter out records.
- NULL means the handler will not return rows that do not match the
- passed condition.
-
- @note
- CONNECT handles the filtering only for table types that construct
- an SQL or WQL query, but still leaves it to MySQL because only some
- parts of the filter may be relevant.
- The first suballocate finds the position where the string will be
- constructed in the sarea. The second one does make the suballocation
- with the proper length.
- */
-const COND *ha_connect::cond_push(const COND *cond)
-{
- DBUG_ENTER("ha_connect::cond_push");
-
- if (tdbp) {
- PGLOBAL& g= xp->g;
- AMT tty= tdbp->GetAmType();
- bool x= (tty == TYPE_AM_MYX || tty == TYPE_AM_XDBC);
- bool b= (tty == TYPE_AM_WMI || tty == TYPE_AM_ODBC ||
- tty == TYPE_AM_TBL || tty == TYPE_AM_MYSQL ||
- tty == TYPE_AM_PLG || x);
-
- if (b) {
- PCFIL filp= (PCFIL)PlugSubAlloc(g, NULL, sizeof(CONDFIL));
-
- filp->Body= (char*)PlugSubAlloc(g, NULL, (x) ? 128 : 0);
- *filp->Body= 0;
- filp->Op= OP_XX;
- filp->Cmds= NULL;
-
- if (CheckCond(g, filp, tty, (Item *)cond)) {
- if (xtrace)
- htrc("cond_push: %s\n", filp->Body);
-
- if (!x)
- PlugSubAlloc(g, NULL, strlen(filp->Body) + 1);
- else
- cond= NULL; // Does this work?
-
- tdbp->SetCondFil(filp);
- } else if (x && cond)
- tdbp->SetCondFil(filp); // Wrong filter
-
- } else
- tdbp->SetFilter(CondFilter(g, (Item *)cond));
-
- } // endif tdbp
-
- // Let MySQL do the filtering
- DBUG_RETURN(cond);
-} // end of cond_push
-
-/**
- Number of rows in table. It will only be called if
- (table_flags() & (HA_HAS_RECORDS | HA_STATS_RECORDS_IS_EXACT)) != 0
-*/
-ha_rows ha_connect::records()
-{
- if (!valid_info)
- info(HA_STATUS_VARIABLE);
-
- if (tdbp && tdbp->Cardinality(NULL))
- return stats.records;
- else
- return HA_POS_ERROR;
-
-} // end of records
-
-
-/**
- Return an error message specific to this handler.
-
- @param error error code previously returned by handler
- @param buf pointer to String where to add error message
-
- @return
- Returns true if this is a temporary error
-*/
-bool ha_connect::get_error_message(int error, String* buf)
-{
- DBUG_ENTER("ha_connect::get_error_message");
-
- 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
-
-
-/**
- @brief
- Used for opening tables. The name will be the name of the file.
-
- @details
- A table is opened when it needs to be opened; e.g. when a request comes in
- for a SELECT on the table (tables are not open and closed for each request,
- they are cached).
-
- Called from handler.cc by handler::ha_open(). The server opens all tables by
- calling ha_open() which then calls the handler specific open().
-
- @note
- For CONNECT no open can be done here because field information is not yet
- updated. >>>>> TO BE CHECKED <<<<<
- (Thread information could be get by using 'ha_thd')
-
- @see
- handler::ha_open() in handler.cc
-*/
-int ha_connect::open(const char *name, int mode, uint test_if_locked)
-{
- int rc= 0;
- DBUG_ENTER("ha_connect::open");
-
- if (xtrace)
- htrc("open: name=%s mode=%d test=%u\n", name, mode, test_if_locked);
-
- if (!(share= get_share()))
- DBUG_RETURN(1);
-
- thr_lock_data_init(&share->lock,&lock,NULL);
-
- // Try to get the user if possible
- xp= GetUser(ha_thd(), xp);
- PGLOBAL g= (xp) ? xp->g : NULL;
-
- // Try to set the database environment
- if (g) {
- rc= (CntCheckDB(g, this, name)) ? (-2) : 0;
-
- if (g->Mrr) {
- // This should only happen for the mrr secondary handler
- mrr= true;
- g->Mrr= false;
- } else
- mrr= false;
-
- } else
- rc= HA_ERR_INTERNAL_ERROR;
-
- DBUG_RETURN(rc);
-} // end of open
-
-/**
- @brief
- Make the indexes for this table
-*/
-int ha_connect::optimize(THD* thd, HA_CHECK_OPT* check_opt)
-{
- int rc= 0;
- PGLOBAL& g= xp->g;
- PDBUSER dup= PlgGetUser(g);
-
- // Ignore error on the opt file
- dup->Check &= ~CHK_OPT;
- tdbp= GetTDB(g);
- dup->Check |= CHK_OPT;
-
- if (tdbp) {
- bool b= ((PTDBASE)tdbp)->GetDef()->Indexable();
-
- if ((rc= ((PTDBASE)tdbp)->ResetTableOpt(g, true, b))) {
- if (rc == RC_INFO) {
- push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
- rc= 0;
- } else
- rc= HA_ERR_INTERNAL_ERROR;
-
- } // endif rc
-
- } else
- rc= HA_ERR_INTERNAL_ERROR;
-
- return rc;
-} // end of optimize
-
-/**
- @brief
- Closes a table.
-
- @details
- Called from sql_base.cc, sql_select.cc, and table.cc. In sql_select.cc it is
- only used to close up temporary tables or during the process where a
- temporary table is converted over to being a myisam table.
-
- For sql_base.cc look at close_data_tables().
-
- @see
- sql_base.cc, sql_select.cc and table.cc
-*/
-int ha_connect::close(void)
-{
- int rc= 0;
- DBUG_ENTER("ha_connect::close");
-
- // If this is called by a later query, the table may have
- // been already closed and the tdbp is not valid anymore.
- if (tdbp && xp->last_query_id == valid_query_id)
- rc= CloseTable(xp->g);
-
- DBUG_RETURN(rc);
-} // end of close
-
-
-/**
- @brief
- write_row() inserts a row. No extra() hint is given currently if a bulk load
- is happening. buf() is a byte array of data. You can use the field
- information to extract the data from the native byte array type.
-
- @details
- Example of this would be:
- @code
- for (Field **field=table->field ; *field ; field++)
- {
- ...
- }
- @endcode
-
- See ha_tina.cc for an example of extracting all of the data as strings.
- ha_berekly.cc has an example of how to store it intact by "packing" it
- for ha_berkeley's own native storage type.
-
- See the note for update_row() on auto_increments and timestamps. This
- case also applies to write_row().
-
- Called from item_sum.cc, item_sum.cc, sql_acl.cc, sql_insert.cc,
- sql_insert.cc, sql_select.cc, sql_table.cc, sql_udf.cc, and sql_update.cc.
-
- @see
- item_sum.cc, item_sum.cc, sql_acl.cc, sql_insert.cc,
- sql_insert.cc, sql_select.cc, sql_table.cc, sql_udf.cc and sql_update.cc
-*/
-int ha_connect::write_row(uchar *buf)
-{
- int rc= 0;
- 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())
- CloseTable(g);
-
- if ((rc= OpenTable(g)))
- DBUG_RETURN(rc);
-
- } // endif isopened
-
- if (tdbp->GetMode() == MODE_ANY)
- DBUG_RETURN(0);
-
-#if 0 // AUTO_INCREMENT NIY
- if (table->next_number_field && buf == table->record[0]) {
- int error;
-
- if ((error= update_auto_increment()))
- return error;
-
- } // endif nex_number_field
-#endif // 0
-
- // Set column values from the passed pseudo record
- if ((rc= ScanRecord(g, buf)))
- DBUG_RETURN(rc);
-
- // Return result code from write operation
- if (CntWriteRow(g, tdbp)) {
- DBUG_PRINT("write_row", ("%s", g->Message));
- htrc("write_row: %s\n", g->Message);
- rc= HA_ERR_INTERNAL_ERROR;
- } // endif RC
-
- DBUG_RETURN(rc);
-} // end of write_row
-
-
-/**
- @brief
- Yes, update_row() does what you expect, it updates a row. old_data will have
- the previous row record in it, while new_data will have the newest data in it.
- Keep in mind that the server can do updates based on ordering if an ORDER BY
- clause was used. Consecutive ordering is not guaranteed.
-
- @details
- Currently new_data will not have an updated auto_increament record, or
- and updated timestamp field. You can do these for example by doing:
- @code
- if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
- table->timestamp_field->set_time();
- if (table->next_number_field && record == table->record[0])
- update_auto_increment();
- @endcode
-
- Called from sql_select.cc, sql_acl.cc, sql_update.cc, and sql_insert.cc.
-
- @see
- sql_select.cc, sql_acl.cc, sql_update.cc and sql_insert.cc
-*/
-int ha_connect::update_row(const uchar *old_data, uchar *new_data)
-{
- int rc= 0;
- PGLOBAL& g= xp->g;
- DBUG_ENTER("ha_connect::update_row");
-
- if (xtrace > 1)
- htrc("update_row: old=%s new=%s\n", old_data, new_data);
-
- // Check values for possible change in indexed column
- if ((rc= CheckRecord(g, old_data, new_data)))
- return rc;
-
- if (CntUpdateRow(g, tdbp)) {
- DBUG_PRINT("update_row", ("%s", g->Message));
- htrc("update_row CONNECT: %s\n", g->Message);
- rc= HA_ERR_INTERNAL_ERROR;
- } // endif RC
-
- DBUG_RETURN(rc);
-} // end of update_row
-
-
-/**
- @brief
- This will delete a row. buf will contain a copy of the row to be deleted.
- The server will call this right after the current row has been called (from
- either a previous rnd_nexT() or index call).
-
- @details
- If you keep a pointer to the last row or can access a primary key it will
- make doing the deletion quite a bit easier. Keep in mind that the server does
- not guarantee consecutive deletions. ORDER BY clauses can be used.
-
- Called in sql_acl.cc and sql_udf.cc to manage internal table
- information. Called in sql_delete.cc, sql_insert.cc, and
- sql_select.cc. In sql_select it is used for removing duplicates
- while in insert it is used for REPLACE calls.
-
- @see
- sql_acl.cc, sql_udf.cc, sql_delete.cc, sql_insert.cc and sql_select.cc
-*/
-int ha_connect::delete_row(const uchar *buf)
-{
- int rc= 0;
- DBUG_ENTER("ha_connect::delete_row");
-
- if (CntDeleteRow(xp->g, tdbp, false)) {
- rc= HA_ERR_INTERNAL_ERROR;
- htrc("delete_row CONNECT: %s\n", xp->g->Message);
- } // endif DeleteRow
-
- DBUG_RETURN(rc);
-} // end of delete_row
-
-
-/****************************************************************************/
-/* We seem to come here at the begining of an index use. */
-/****************************************************************************/
-int ha_connect::index_init(uint idx, bool sorted)
-{
- int rc;
- PGLOBAL& g= xp->g;
- DBUG_ENTER("index_init");
-
- if (xtrace)
- htrc("index_init: this=%p idx=%u sorted=%d\n", this, idx, 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) {
- DBUG_PRINT("index_init", ("%s", g->Message));
- htrc("index_init CONNECT: %s\n", g->Message);
- active_index= MAX_KEY;
- rc= HA_ERR_INTERNAL_ERROR;
- } else {
- if (((PTDBDOX)tdbp)->To_Kindex->GetNum_K()) {
- if (((PTDBASE)tdbp)->GetFtype() != RECFM_NAF)
- ((PTDBDOX)tdbp)->GetTxfp()->ResetBuffer(g);
-
- active_index= idx;
- } else // Void table
- indexing= 0;
-
- rc= 0;
- } // endif indexing
-
- if (xtrace)
- htrc("index_init: rc=%d indexing=%d active_index=%d\n",
- rc, indexing, active_index);
-
- DBUG_RETURN(rc);
-} // end of index_init
-
-/****************************************************************************/
-/* We seem to come here at the end of an index use. */
-/****************************************************************************/
-int ha_connect::index_end()
-{
- DBUG_ENTER("index_end");
- active_index= MAX_KEY;
- ds_mrr.dsmrr_close();
- DBUG_RETURN(rnd_end());
-} // end of index_end
-
-
-/****************************************************************************/
-/* This is internally called by all indexed reading functions. */
-/****************************************************************************/
-int ha_connect::ReadIndexed(uchar *buf, OPVAL op, const uchar *key, uint key_len)
-{
- int rc;
-
-//statistic_increment(ha_read_key_count, &LOCK_status);
-
- switch (CntIndexRead(xp->g, tdbp, op, key, (int)key_len, mrr)) {
- case RC_OK:
- xp->fnd++;
- rc= MakeRecord((char*)buf);
- break;
- case RC_EF: // End of file
- rc= HA_ERR_END_OF_FILE;
- break;
- case RC_NF: // Not found
- xp->nfd++;
- rc= (op == OP_SAME) ? HA_ERR_END_OF_FILE : HA_ERR_KEY_NOT_FOUND;
- break;
- default: // Read error
- DBUG_PRINT("ReadIndexed", ("%s", xp->g->Message));
- htrc("ReadIndexed: %s\n", xp->g->Message);
- rc= HA_ERR_INTERNAL_ERROR;
- break;
- } // endswitch RC
-
- if (xtrace > 1)
- htrc("ReadIndexed: op=%d rc=%d\n", op, rc);
-
- table->status= (rc == RC_OK) ? 0 : STATUS_NOT_FOUND;
- return rc;
-} // end of ReadIndexed
-
-
-#ifdef NOT_USED
-/**
- @brief
- Positions an index cursor to the index specified in the handle. Fetches the
- row if available. If the key value is null, begin at the first key of the
- index.
-*/
-int ha_connect::index_read_map(uchar *buf, const uchar *key,
- key_part_map keypart_map __attribute__((unused)),
- enum ha_rkey_function find_flag
- __attribute__((unused)))
-{
- DBUG_ENTER("ha_connect::index_read");
- DBUG_RETURN(HA_ERR_WRONG_COMMAND);
-}
-#endif // NOT_USED
-
-
-/****************************************************************************/
-/* This is called by handler::index_read_map. */
-/****************************************************************************/
-int ha_connect::index_read(uchar * buf, const uchar * key, uint key_len,
- enum ha_rkey_function find_flag)
-{
- int rc;
- OPVAL op= OP_XX;
- DBUG_ENTER("ha_connect::index_read");
-
- switch(find_flag) {
- case HA_READ_KEY_EXACT: op= OP_EQ; break;
- case HA_READ_AFTER_KEY: op= OP_GT; break;
- case HA_READ_KEY_OR_NEXT: op= OP_GE; break;
- default: DBUG_RETURN(-1); break;
- } // endswitch find_flag
-
- if (xtrace > 1)
- htrc("%p index_read: op=%d\n", this, op);
-
- if (indexing > 0)
- rc= ReadIndexed(buf, op, key, key_len);
- else
- rc= HA_ERR_INTERNAL_ERROR;
-
- DBUG_RETURN(rc);
-} // end of index_read
-
-
-/**
- @brief
- Used to read forward through the index.
-*/
-int ha_connect::index_next(uchar *buf)
-{
- int rc;
- DBUG_ENTER("ha_connect::index_next");
- //statistic_increment(ha_read_next_count, &LOCK_status);
-
- if (indexing > 0)
- rc= ReadIndexed(buf, OP_NEXT);
- else if (!indexing)
- rc= rnd_next(buf);
- else
- rc= HA_ERR_INTERNAL_ERROR;
-
- DBUG_RETURN(rc);
-} // end of index_next
-
-
-#ifdef NOT_USED
-/**
- @brief
- Used to read backwards through the index.
-*/
-int ha_connect::index_prev(uchar *buf)
-{
- DBUG_ENTER("ha_connect::index_prev");
- DBUG_RETURN(HA_ERR_WRONG_COMMAND);
-}
-#endif // NOT_USED
-
-
-/**
- @brief
- index_first() asks for the first key in the index.
-
- @details
- Called from opt_range.cc, opt_sum.cc, sql_handler.cc, and sql_select.cc.
-
- @see
- opt_range.cc, opt_sum.cc, sql_handler.cc and sql_select.cc
-*/
-int ha_connect::index_first(uchar *buf)
-{
- int rc;
- DBUG_ENTER("ha_connect::index_first");
-
- if (indexing > 0)
- rc= ReadIndexed(buf, OP_FIRST);
- else if (indexing < 0)
- rc= HA_ERR_INTERNAL_ERROR;
- else if (CntRewindTable(xp->g, tdbp)) {
- table->status= STATUS_NOT_FOUND;
- rc= HA_ERR_INTERNAL_ERROR;
- } else
- rc= rnd_next(buf);
-
- DBUG_RETURN(rc);
-} // end of index_first
-
-
-#ifdef NOT_USED
-/**
- @brief
- index_last() asks for the last key in the index.
-
- @details
- Called from opt_range.cc, opt_sum.cc, sql_handler.cc, and sql_select.cc.
-
- @see
- opt_range.cc, opt_sum.cc, sql_handler.cc and sql_select.cc
-*/
-int ha_connect::index_last(uchar *buf)
-{
- DBUG_ENTER("ha_connect::index_last");
- DBUG_RETURN(HA_ERR_WRONG_COMMAND);
-}
-#endif // NOT_USED
-
-
-/****************************************************************************/
-/* This is called to get more rows having the same index value. */
-/****************************************************************************/
-int ha_connect::index_next_same(uchar *buf, const uchar *key, uint keylen)
-{
- int rc;
- DBUG_ENTER("ha_connect::index_next_same");
-//statistic_increment(ha_read_next_count, &LOCK_status);
-
- if (!indexing)
- rc= rnd_next(buf);
- else if (indexing > 0)
- rc= ReadIndexed(buf, OP_SAME);
- else
- rc= HA_ERR_INTERNAL_ERROR;
-
- DBUG_RETURN(rc);
-} // end of index_next_same
-
-
-/**
- @brief
- rnd_init() is called when the system wants the storage engine to do a table
- scan. See the example in the introduction at the top of this file to see when
- rnd_init() is called.
-
- @details
- Called from filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc,
- and sql_update.cc.
-
- @note
- We always call open and extern_lock/start_stmt before comming here.
-
- @see
- filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc and sql_update.cc
-*/
-int ha_connect::rnd_init(bool scan)
-{
- int rc;
- PGLOBAL g= ((table && table->in_use) ? GetPlug(table->in_use, xp) :
- (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)
- htrc("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);
-
- // Do not close the table if it was opened yet (locked?)
- if (IsOpened()) {
- if (tdbp->OpenDB(g)) // Rewind table
- DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
- else
- DBUG_RETURN(0);
-
- } else if (xp->CheckQuery(valid_query_id))
- tdbp= NULL; // Not valid anymore
-
- // When updating, to avoid skipped update, force the table
- // handler to retrieve write-only fields to be able to compare
- // records and detect data change.
- if (xmod == MODE_UPDATE)
- bitmap_union(table->read_set, table->write_set);
-
- if ((rc= OpenTable(g, xmod == MODE_DELETE)))
- DBUG_RETURN(rc);
-
- xp->nrd= xp->fnd= xp->nfd= 0;
- xp->tb1= my_interval_timer();
- DBUG_RETURN(0);
-} // end of rnd_init
-
-/**
- @brief
- Not described.
-
- @note
- The previous version said:
- Stop scanning of table. Note that this may be called several times during
- execution of a sub select.
- =====> This has been moved to external lock to avoid closing subselect tables.
-*/
-int ha_connect::rnd_end()
-{
- int rc= 0;
- DBUG_ENTER("ha_connect::rnd_end");
-
- // If this is called by a later query, the table may have
- // been already closed and the tdbp is not valid anymore.
-// if (tdbp && xp->last_query_id == valid_query_id)
-// rc= CloseTable(xp->g);
-
- ds_mrr.dsmrr_close();
- DBUG_RETURN(rc);
-} // end of rnd_end
-
-
-/**
- @brief
- This is called for each row of the table scan. When you run out of records
- you should return HA_ERR_END_OF_FILE. Fill buff up with the row information.
- The Field structure for the table is the key to getting data into buf
- in a manner that will allow the server to understand it.
-
- @details
- Called from filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc,
- and sql_update.cc.
-
- @see
- filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc and sql_update.cc
-*/
-int ha_connect::rnd_next(uchar *buf)
-{
- int rc;
- DBUG_ENTER("ha_connect::rnd_next");
-//statistic_increment(ha_read_rnd_next_count, &LOCK_status);
-
- if (tdbp->GetMode() == MODE_ANY) {
- // We will stop on next read
- if (!stop) {
- stop= true;
- DBUG_RETURN(RC_OK);
- } else
- DBUG_RETURN(HA_ERR_END_OF_FILE);
-
- } // endif Mode
-
- switch (CntReadNext(xp->g, tdbp)) {
- case RC_OK:
- rc= MakeRecord((char*)buf);
- break;
- case RC_EF: // End of file
- rc= HA_ERR_END_OF_FILE;
- break;
- case RC_NF: // Not found
- rc= HA_ERR_RECORD_DELETED;
- break;
- default: // Read error
- htrc("rnd_next CONNECT: %s\n", xp->g->Message);
- rc= (records()) ? HA_ERR_INTERNAL_ERROR : HA_ERR_END_OF_FILE;
- break;
- } // endswitch RC
-
- if (xtrace > 1 && (rc || !(xp->nrd++ % 16384))) {
- ulonglong tb2= my_interval_timer();
- double elapsed= (double) (tb2 - xp->tb1) / 1000000000ULL;
- DBUG_PRINT("rnd_next", ("rc=%d nrd=%u fnd=%u nfd=%u sec=%.3lf\n",
- rc, (uint)xp->nrd, (uint)xp->fnd,
- (uint)xp->nfd, elapsed));
- htrc("rnd_next: rc=%d nrd=%u fnd=%u nfd=%u sec=%.3lf\n",
- rc, (uint)xp->nrd, (uint)xp->fnd,
- (uint)xp->nfd, elapsed);
- xp->tb1= tb2;
- xp->fnd= xp->nfd= 0;
- } // endif nrd
-
- table->status= (!rc) ? 0 : STATUS_NOT_FOUND;
- DBUG_RETURN(rc);
-} // end of rnd_next
-
-
-/**
- @brief
- position() is called after each call to rnd_next() if the data needs
- to be ordered. You can do something like the following to store
- the position:
- @code
- my_store_ptr(ref, ref_length, current_position);
- @endcode
-
- @details
- The server uses ref to store data. ref_length in the above case is
- the size needed to store current_position. ref is just a byte array
- that the server will maintain. If you are using offsets to mark rows, then
- current_position should be the offset. If it is a primary key like in
- BDB, then it needs to be a primary key.
-
- Called from filesort.cc, sql_select.cc, sql_delete.cc, and sql_update.cc.
-
- @see
- filesort.cc, sql_select.cc, sql_delete.cc and sql_update.cc
-*/
-void ha_connect::position(const uchar *record)
-{
- DBUG_ENTER("ha_connect::position");
-//if (((PTDBASE)tdbp)->GetDef()->Indexable())
- my_store_ptr(ref, ref_length, (my_off_t)((PTDBASE)tdbp)->GetRecpos());
- DBUG_VOID_RETURN;
-} // end of position
-
-
-/**
- @brief
- This is like rnd_next, but you are given a position to use
- to determine the row. The position will be of the type that you stored in
- ref. You can use my_get_ptr(pos,ref_length) to retrieve whatever key
- or position you saved when position() was called.
-
- @details
- Called from filesort.cc, records.cc, sql_insert.cc, sql_select.cc, and sql_update.cc.
-
- @note
- Is this really useful? It was never called even when sorting.
-
- @see
- filesort.cc, records.cc, sql_insert.cc, sql_select.cc and sql_update.cc
-*/
-int ha_connect::rnd_pos(uchar *buf, uchar *pos)
-{
- int rc;
- PTDBASE tp= (PTDBASE)tdbp;
- DBUG_ENTER("ha_connect::rnd_pos");
-
- if (!tp->SetRecpos(xp->g, (int)my_get_ptr(pos, ref_length)))
- rc= rnd_next(buf);
- else
- rc= HA_ERR_KEY_NOT_FOUND;
-
- DBUG_RETURN(rc);
-} // end of rnd_pos
-
-
-/**
- @brief
- ::info() is used to return information to the optimizer. See my_base.h for
- the complete description.
-
- @details
- Currently this table handler doesn't implement most of the fields really needed.
- SHOW also makes use of this data.
-
- You will probably want to have the following in your code:
- @code
- if (records < 2)
- records= 2;
- @endcode
- The reason is that the server will optimize for cases of only a single
- record. If, in a table scan, you don't know the number of records, it
- will probably be better to set records to two so you can return as many
- records as you need. Along with records, a few more variables you may wish
- to set are:
- records
- deleted
- data_file_length
- index_file_length
- delete_length
- check_time
- Take a look at the public variables in handler.h for more information.
-
- Called in filesort.cc, ha_heap.cc, item_sum.cc, opt_sum.cc, sql_delete.cc,
- sql_delete.cc, sql_derived.cc, sql_select.cc, sql_select.cc, sql_select.cc,
- sql_select.cc, sql_select.cc, sql_show.cc, sql_show.cc, sql_show.cc, sql_show.cc,
- sql_table.cc, sql_union.cc, and sql_update.cc.
-
- @see
- filesort.cc, ha_heap.cc, item_sum.cc, opt_sum.cc, sql_delete.cc, sql_delete.cc,
- sql_derived.cc, sql_select.cc, sql_select.cc, sql_select.cc, sql_select.cc,
- sql_select.cc, sql_show.cc, sql_show.cc, sql_show.cc, sql_show.cc, sql_table.cc,
- sql_union.cc and sql_update.cc
-*/
-int ha_connect::info(uint flag)
-{
- bool pure= false;
- PGLOBAL g= GetPlug((table) ? table->in_use : NULL, xp);
-
- DBUG_ENTER("ha_connect::info");
-
- if (xtrace)
- htrc("%p In info: flag=%u valid_info=%d\n", this, flag, valid_info);
-
- if (!valid_info) {
- // tdbp must be available to get updated info
- if (xp->CheckQuery(valid_query_id) || !tdbp) {
- if (xmod == MODE_ANY || xmod == MODE_ALTER) {
- // Pure info, not a query
- pure= true;
- xp->CheckCleanup();
- } // endif xmod
-
- tdbp= GetTDB(g);
- } // endif tdbp
-
- valid_info= CntInfo(g, tdbp, &xinfo);
- } // endif valid_info
-
- if (flag & HA_STATUS_VARIABLE) {
- stats.records= xinfo.records;
- stats.deleted= 0;
- stats.data_file_length= xinfo.data_file_length;
- stats.index_file_length= 0;
- stats.delete_length= 0;
- stats.check_time= 0;
- stats.mean_rec_length= xinfo.mean_rec_length;
- } // endif HA_STATUS_VARIABLE
-
- if (flag & HA_STATUS_CONST) {
- // This is imported from the previous handler and must be reconsidered
- stats.max_data_file_length= 4294967295;
- stats.max_index_file_length= 4398046510080;
- stats.create_time= 0;
- data_file_name= xinfo.data_file_name;
- index_file_name= NULL;
-// sortkey= (uint) - 1; // Table is not sorted
- ref_length= sizeof(int); // Pointer size to row
- table->s->db_options_in_use= 03;
- stats.block_size= 1024;
- table->s->keys_in_use.set_prefix(table->s->keys);
- table->s->keys_for_keyread= table->s->keys_in_use;
-// table->s->keys_for_keyread.subtract(table->s->read_only_keys);
- table->s->db_record_offset= 0;
- } // endif HA_STATUS_CONST
-
- if (flag & HA_STATUS_ERRKEY) {
- errkey= 0;
- } // endif HA_STATUS_ERRKEY
-
- if (flag & HA_STATUS_TIME)
- stats.update_time= 0;
-
- if (flag & HA_STATUS_AUTO)
- stats.auto_increment_value= 1;
-
- if (tdbp && pure)
- CloseTable(g); // Not used anymore
-
- DBUG_RETURN(0);
-} // end of info
-
-
-/**
- @brief
- extra() is called whenever the server wishes to send a hint to
- the storage engine. The myisam engine implements the most hints.
- ha_innodb.cc has the most exhaustive list of these hints.
-
- @note
- This is not yet implemented for CONNECT.
-
- @see
- ha_innodb.cc
-*/
-int ha_connect::extra(enum ha_extra_function operation)
-{
- DBUG_ENTER("ha_connect::extra");
- DBUG_RETURN(0);
-} // end of extra
-
-
-/**
- @brief
- Used to delete all rows in a table, including cases of truncate and cases where
- the optimizer realizes that all rows will be removed as a result of an SQL statement.
-
- @details
- Called from item_sum.cc by Item_func_group_concat::clear(),
- Item_sum_count_distinct::clear(), and Item_func_group_concat::clear().
- Called from sql_delete.cc by mysql_delete().
- Called from sql_select.cc by JOIN::reinit().
- Called from sql_union.cc by st_select_lex_unit::exec().
-
- @see
- Item_func_group_concat::clear(), Item_sum_count_distinct::clear() and
- Item_func_group_concat::clear() in item_sum.cc;
- mysql_delete() in sql_delete.cc;
- JOIN::reinit() in sql_select.cc and
- st_select_lex_unit::exec() in sql_union.cc.
-*/
-int ha_connect::delete_all_rows()
-{
- int rc= 0;
- PGLOBAL g= xp->g;
- DBUG_ENTER("ha_connect::delete_all_rows");
-
- if (tdbp && tdbp->GetUse() == USE_OPEN &&
- tdbp->GetAmType() != TYPE_AM_XML &&
- ((PTDBASE)tdbp)->GetFtype() != RECFM_NAF)
- // Close and reopen the table so it will be deleted
- rc= CloseTable(g);
-
- if (!(rc= OpenTable(g))) {
- if (CntDeleteRow(g, tdbp, true)) {
- htrc("%s\n", g->Message);
- rc= HA_ERR_INTERNAL_ERROR;
- } // endif
-
- } // endif rc
-
- DBUG_RETURN(rc);
-} // end of 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);
-
- switch (type) {
- case TAB_UNDEF:
-// case TAB_CATLG:
- case TAB_PLG:
- case TAB_JCT:
- case TAB_DMY:
- case TAB_NIY:
- my_printf_error(ER_UNKNOWN_ERROR,
- "Unsupported table type %s", MYF(0), options->type);
- return true;
-
- case TAB_DOS:
- case TAB_FIX:
- case TAB_BIN:
- case TAB_CSV:
- case TAB_FMT:
- case TAB_DBF:
- case TAB_XML:
- case TAB_INI:
- case TAB_VEC:
- 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;
-
- /* Fall through to check FILE_ACL */
- case TAB_ODBC:
- case TAB_MYSQL:
- case TAB_DIR:
- case TAB_MAC:
- case TAB_WMI:
- case TAB_OEM:
- return check_access(thd, FILE_ACL, db, NULL, NULL, 0, 0);
-
- // This is temporary until a solution is found
- case TAB_TBL:
- case TAB_XCL:
- case TAB_PRX:
- case TAB_OCCUR:
- case TAB_PIVOT:
- return false;
- } // endswitch type
-
- my_printf_error(ER_UNKNOWN_ERROR, "check_privileges failed", MYF(0));
- return true;
-} // end of check_privileges
-
-// Check that two indexes are equivalent
-bool ha_connect::IsSameIndex(PIXDEF xp1, PIXDEF xp2)
-{
- bool b= true;
- PKPDEF kp1, kp2;
-
- if (stricmp(xp1->Name, xp2->Name))
- b= false;
- else if (xp1->Nparts != xp2->Nparts ||
- xp1->MaxSame != xp2->MaxSame ||
- xp1->Unique != xp2->Unique)
- b= false;
- else for (kp1= xp1->ToKeyParts, kp2= xp2->ToKeyParts;
- b && (kp1 || kp2);
- kp1= kp1->Next, kp2= kp2->Next)
- if (!kp1 || !kp2)
- b= false;
- else if (stricmp(kp1->Name, kp2->Name))
- b= false;
- else if (kp1->Klen != kp2->Klen)
- b= false;
-
- 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);
- htrc("%p check_mode: cmdtype=%d\n", this, thd_sql_command(thd));
- htrc("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:
- 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;
- case SQLCOM_ALTER_TABLE:
- newmode= MODE_ALTER;
- break;
- default:
- htrc("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:
- *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;
- case SQLCOM_ALTER_TABLE:
- *chk= true;
- newmode= MODE_ALTER;
- break;
- default:
- htrc("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)
- htrc("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
- that can handle transacations look at ha_berkely.cc to see how you will
- want to go about doing this. Otherwise you should consider calling flock()
- here. Hint: Read the section "locking functions for mysql" in lock.cc to understand
- this.
-
- @details
- Called from lock.cc by lock_external() and unlock_external(). Also called
- from sql_table.cc by copy_data_between_tables().
-
- @note
- Following what we did in the MySQL XDB handler, we use this call to actually
- physically open the table. This could be reconsider when finalizing this handler
- design, which means we have a better understanding of what MariaDB does.
-
- @see
- lock.cc by lock_external() and unlock_external() in lock.cc;
- the section "locking functions for mysql" in lock.cc;
- copy_data_between_tables() in sql_table.cc.
-*/
-int ha_connect::external_lock(THD *thd, int lock_type)
-{
- int rc= 0;
- bool xcheck=false, cras= false;
- MODE newmode;
- PTOS options= GetTableOptionStruct(table);
- PGLOBAL g= GetPlug(thd, xp);
- DBUG_ENTER("ha_connect::external_lock");
-
- DBUG_ASSERT(thd == current_thd);
-
- if (xtrace)
- htrc("external_lock: this=%p thd=%p xp=%p g=%p lock_type=%d\n",
- this, thd, xp, g, lock_type);
-
- if (!g)
- DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
-
- // Action will depend on lock_type
- switch (lock_type) {
- case F_WRLCK:
- newmode= MODE_WRITE;
- break;
- case F_RDLCK:
- newmode= MODE_READ;
- break;
- case F_UNLCK:
- default:
- newmode= MODE_ANY;
- break;
- } // endswitch mode
-
- if (newmode == MODE_ANY) {
- int sqlcom= thd_sql_command(thd);
-
- // This is unlocking, do it by closing the table
- if (xp->CheckQueryID() && sqlcom != SQLCOM_UNLOCK_TABLES
- && sqlcom != SQLCOM_LOCK_TABLES
- && sqlcom != SQLCOM_DROP_TABLE) {
- sprintf(g->Message, "external_lock: unexpected command %d", sqlcom);
- push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
- DBUG_RETURN(0);
- } 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());
-// DBUG_RETURN(HA_ERR_INTERNAL_ERROR); causes assert error
- push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
- DBUG_RETURN(0);
- } // endif Indexable
-
- bool oldsep= ((PCHK)g->Xchk)->oldsep;
- bool newsep= ((PCHK)g->Xchk)->newsep;
- PTDBDOS tdp= (PTDBDOS)tdbp;
-
- PDOSDEF ddp= (PDOSDEF)tdp->GetDef();
- PIXDEF xp, xp1, xp2, drp=NULL, adp= NULL;
- PIXDEF oldpix= ((PCHK)g->Xchk)->oldpix;
- PIXDEF newpix= ((PCHK)g->Xchk)->newpix;
- PIXDEF *xlst, *xprc;
-
- ddp->SetIndx(oldpix);
-
- if (oldsep != newsep) {
- // All indexes have to be remade
- ddp->DeleteIndexFile(g, NULL);
- oldpix= NULL;
- ddp->SetIndx(NULL);
- SetBooleanOption("Sepindex", newsep);
- } else if (newsep) {
- // Make the list of dropped indexes
- xlst= &drp; xprc= &oldpix;
-
- for (xp2= oldpix; xp2; xp2= xp) {
- for (xp1= newpix; xp1; xp1= xp1->Next)
- if (IsSameIndex(xp1, xp2))
- break; // Index not to drop
-
- xp= xp2->GetNext();
-
- if (!xp1) {
- *xlst= xp2;
- *xprc= xp;
- *(xlst= &xp2->Next)= NULL;
- } else
- xprc= &xp2->Next;
-
- } // endfor xp2
-
- if (drp) {
- // Here we erase the index files
- ddp->DeleteIndexFile(g, drp);
- } // endif xp1
-
- } else if (oldpix) {
- // TODO: optimize the case of just adding new indexes
- if (!newpix)
- ddp->DeleteIndexFile(g, NULL);
-
- oldpix= NULL; // To remake all indexes
- ddp->SetIndx(NULL);
- } // endif sepindex
-
- // Make the list of new created indexes
- xlst= &adp; xprc= &newpix;
-
- for (xp1= newpix; xp1; xp1= xp) {
- for (xp2= oldpix; xp2; xp2= xp2->Next)
- if (IsSameIndex(xp1, xp2))
- break; // Index already made
-
- xp= xp1->Next;
-
- if (!xp2) {
- *xlst= xp1;
- *xprc= xp;
- *(xlst= &xp1->Next)= NULL;
- } else
- xprc= &xp1->Next;
-
- } // endfor xp1
-
- if (adp)
- // Here we do make the new indexes
- if (tdp->MakeIndex(g, adp, true) == RC_FX) {
- // Make it a warning to avoid crash
- push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
- 0, g->Message);
- rc= 0;
- } // endif MakeIndex
-
- } // endif Tdbp
-
- } // endelse Xchk
-
- if (CloseTable(g)) {
- // This is an error while builing index
- // Make it a warning to avoid crash
- push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
- rc= 0;
- } // endif Close
-
- locked= 0;
- DBUG_RETURN(rc);
- } // endif MODE_ANY
-
- DBUG_ASSERT(table && table->s);
-
- if (check_privileges(thd, options, table->s->db.str)) {
- strcpy(g->Message, "This operation requires the FILE privilege");
- htrc("%s\n", g->Message);
- DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
- } // endif check_privileges
-
- // Table mode depends on the query type
- newmode= CheckMode(g, thd, newmode, &xcheck, &cras);
-
- 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()) {
- tdbp= NULL;
- valid_info= false;
- } // endif CheckCleanup
-
-#if 0
- if (xcheck) {
- // This must occur after CheckCleanup
- 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) {
-#if 0
- htrc("xcheck=%d cras=%d\n", xcheck, cras);
-
- if (xcheck)
- htrc("oldsep=%d oldpix=%p\n",
- ((PCHK)g->Xchk)->oldsep, ((PCHK)g->Xchk)->oldpix);
-#endif // 0
- htrc("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))) {
- htrc("%p external_lock: %s\n", this, g->Message);
- rc= HA_ERR_INTERNAL_ERROR;
- // This can NOT be called without open called first, but
- // the table can have been closed since then
- } else if (!tdbp || xp->CheckQuery(valid_query_id) || xmod != newmode) {
- if (tdbp) {
- // If this is called by a later query, the table may have
- // been already closed and the tdbp is not valid anymore.
- if (xp->last_query_id == valid_query_id)
- rc= CloseTable(g);
- else
- tdbp= NULL;
-
- } // endif tdbp
-
- xmod= newmode;
-
- // Delay open until used fields are known
- } // endif tdbp
-
- if (xtrace)
- htrc("external_lock: rc=%d\n", rc);
-
- DBUG_RETURN(rc);
-} // end of external_lock
-
-
-/**
- @brief
- The idea with handler::store_lock() is: The statement decides which locks
- should be needed for the table. For updates/deletes/inserts we get WRITE
- locks, for SELECT... we get read locks.
-
- @details
- Before adding the lock into the table lock handler (see thr_lock.c),
- mysqld calls store lock with the requested locks. Store lock can now
- modify a write lock to a read lock (or some other lock), ignore the
- lock (if we don't want to use MySQL table locks at all), or add locks
- for many tables (like we do when we are using a MERGE handler).
-
- Berkeley DB, for example, changes all WRITE locks to TL_WRITE_ALLOW_WRITE
- (which signals that we are doing WRITES, but are still allowing other
- readers and writers).
-
- When releasing locks, store_lock() is also called. In this case one
- usually doesn't have to do anything.
-
- In some exceptional cases MySQL may send a request for a TL_IGNORE;
- This means that we are requesting the same lock as last time and this
- should also be ignored. (This may happen when someone does a flush
- table when we have opened a part of the tables, in which case mysqld
- closes and reopens the tables and tries to get the same locks at last
- time). In the future we will probably try to remove this.
-
- Called from lock.cc by get_lock_data().
-
- @note
- In this method one should NEVER rely on table->in_use, it may, in fact,
- refer to a different thread! (this happens if get_lock_data() is called
- from mysql_lock_abort_for_thread() function)
-
- @see
- get_lock_data() in lock.cc
-*/
-THR_LOCK_DATA **ha_connect::store_lock(THD *thd,
- THR_LOCK_DATA **to,
- enum thr_lock_type lock_type)
-{
- if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK)
- lock.type=lock_type;
- *to++ = &lock;
- return to;
-}
-
-
-/**
- Searches for a pointer to the last occurrence of the
- character c in the string src.
- Returns true on failure, false on success.
-*/
-static bool
-strnrchr(LEX_CSTRING *ls, const char *src, size_t length, int c)
-{
- const char *srcend, *s;
- for (s= srcend= src + length; s > src; s--)
- {
- if (s[-1] == c)
- {
- ls->str= s;
- ls->length= srcend - s;
- return false;
- }
- }
- return true;
-}
-
-
-/**
- Split filename into database and table name.
-*/
-static bool
-filename_to_dbname_and_tablename(const char *filename,
- char *database, size_t database_size,
- char *table, size_t table_size)
-{
-#if defined(WIN32)
- char slash= '\\';
-#else // !WIN32
- char slash= '/';
-#endif // !WIN32
- LEX_CSTRING d, t;
- size_t length= strlen(filename);
-
- /* Find filename - the rightmost directory part */
- if (strnrchr(&t, filename, length, slash) || t.length + 1 > table_size)
- return true;
- memcpy(table, t.str, t.length);
- table[t.length]= '\0';
- if (!(length-= t.length))
- return true;
-
- length--; /* Skip slash */
-
- /* Find database name - the second rightmost directory part */
- if (strnrchr(&d, filename, length, slash) || d.length + 1 > database_size)
- return true;
- memcpy(database, d.str, d.length);
- database[d.length]= '\0';
- return false;
-} // end of filename_to_dbname_and_tablename
-
-/**
- @brief
- Used to delete or rename a table. By the time delete_table() has been
- called all opened references to this table will have been closed
- (and your globally shared references released) ===> too bad!!!
- The variable name will just be the name of the table.
- You will need to remove or rename any files you have created at
- this point.
-
- @details
- If you do not implement this, the default delete_table() is called from
- handler.cc and it will delete all files with the file extensions returned
- by bas_ext().
-
- Called from handler.cc by delete_table and ha_create_table(). Only used
- during create if the table_flag HA_DROP_BEFORE_CREATE was specified for
- the storage engine.
-
- @see
- delete_table and ha_create_table() in handler.cc
-*/
-int ha_connect::delete_or_rename_table(const char *name, const char *to)
-{
- DBUG_ENTER("ha_connect::delete_or_rename_table");
- 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)
- htrc("rename_table: this=%p thd=%p sqlcom=%d from=%s to=%s\n",
- this, thd, sqlcom, name, to);
- else
- htrc("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 == '#' && sqlcom == SQLCOM_CREATE_INDEX)))
- DBUG_RETURN(0);
-
- if (filename_to_dbname_and_tablename(name, db, sizeof(db),
- tabname, sizeof(tabname))
- || (*tabname == '#' && sqlcom == SQLCOM_CREATE_INDEX))
- DBUG_RETURN(0);
-
- // 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;
-
- key_length= tdc_create_key(key, db, tabname);
-
- // share contains the option struct that we need
- if (!(share= alloc_table_share(db, tabname, key, key_length)))
- DBUG_RETURN(rc);
-
-#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();
-
- free_table_share(share);
- } else // Temporary file
- ok= true;
-
- if (ok) {
- // Let the base handler do the job
- if (to)
- rc= handler::rename_table(name, to);
- else if ((rc= handler::delete_table(name)) == ENOENT)
- rc= 0; // No files is not an error for CONNECT
-
- } // endif ok
-
- DBUG_RETURN(rc);
-} // end of delete_or_rename_table
-
-int ha_connect::delete_table(const char *name)
-{
- return delete_or_rename_table(name, NULL);
-} // end of delete_table
-
-int ha_connect::rename_table(const char *from, const char *to)
-{
- return delete_or_rename_table(from, to);
-} // end of rename_table
-
-/**
- @brief
- Given a starting key and an ending key, estimate the number of rows that
- will exist between the two keys.
-
- @details
- end_key may be empty, in which case determine if start_key matches any rows.
-
- Called from opt_range.cc by check_quick_keys().
-
- @see
- check_quick_keys() in opt_range.cc
-*/
-ha_rows ha_connect::records_in_range(uint inx, key_range *min_key,
- key_range *max_key)
-{
- ha_rows rows;
- DBUG_ENTER("ha_connect::records_in_range");
-
- if (indexing < 0 || inx != active_index)
- index_init(inx, false);
-
- if (xtrace)
- htrc("records_in_range: inx=%d indexing=%d\n", inx, indexing);
-
- if (indexing > 0) {
- int nval;
- uint len[2];
- const uchar *key[2];
- bool incl[2];
- key_part_map kmap[2];
-
- key[0]= (min_key) ? min_key->key : NULL;
- key[1]= (max_key) ? max_key->key : NULL;
- len[0]= (min_key) ? min_key->length : 0;
- len[1]= (max_key) ? max_key->length : 0;
- incl[0]= (min_key) ? (min_key->flag == HA_READ_KEY_EXACT) : false;
- incl[1]= (max_key) ? (max_key->flag == HA_READ_AFTER_KEY) : false;
- kmap[0]= (min_key) ? min_key->keypart_map : 0;
- kmap[1]= (max_key) ? max_key->keypart_map : 0;
-
- if ((nval= CntIndexRange(xp->g, tdbp, key, len, incl, kmap)) < 0)
- rows= HA_POS_ERROR;
- else
- rows= (ha_rows)nval;
-
- } else if (indexing < 0)
- rows= HA_POS_ERROR;
- else
- rows= 100000000; // Don't use missing index
-
- DBUG_RETURN(rows);
-} // end of records_in_range
-
-/**
- Convert an ISO-8859-1 column name to UTF-8
-*/
-static char *encode(PGLOBAL g, char *cnm)
- {
- char *buf= (char*)PlugSubAlloc(g, NULL, strlen(cnm) * 3);
- uint dummy_errors;
- uint32 len= copy_and_convert(buf, strlen(cnm) * 3,
- &my_charset_utf8_general_ci,
- cnm, strlen(cnm),
- &my_charset_latin1,
- &dummy_errors);
- buf[len]= '\0';
- return buf;
- } // end of Encode
-
-/**
- Store field definition for create.
-
- @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,
- char v)
-{
- register Create_field *new_field;
- char *length, *decimals= NULL;
- enum_field_types type;
-//Virtual_column_info *vcol_info= (Virtual_column_info *)vcolinfo;
- engine_option_value *crop;
- LEX_STRING *comment;
- LEX_STRING *field_name;
-
- DBUG_ENTER("ha_connect::add_fields");
-
- if (len) {
- if (!v && typ == TYPE_STRING && len > 255)
- v= 'V'; // Change CHAR to VARCHAR
-
- length= (char*)PlugSubAlloc(g, NULL, 8);
- sprintf(length, "%d", len);
-
- if (typ == TYPE_DOUBLE) {
- decimals= (char*)PlugSubAlloc(g, NULL, 8);
- sprintf(decimals, "%d", min(dec, (min(len, 31) - 1)));
- } // endif dec
-
- } else
- length= NULL;
-
- if (!rem)
- rem= "";
-
- type= PLGtoMYSQL(typ, dbf, v);
- comment= thd->make_lex_string(rem, strlen(rem));
- field_name= thd->make_lex_string(name, strlen(name));
-
- switch (v) {
- case 'Z': type_modifier|= ZEROFILL_FLAG;
- case 'U': type_modifier|= UNSIGNED_FLAG; break;
- } // endswitch v
-
- 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,
- char *dft, char *xtra, int flag, bool dbf, char v)
-{
- char var = (len > 255) ? 'V' : v;
- bool error= false;
- const char *type= PLGtoMYSQLtype(typ, dbf, var);
-
- error|= sql->append('`');
- error|= sql->append(field_name);
- error|= sql->append("` ");
- error|= sql->append(type);
-
- if (len && typ != TYPE_DATE) {
- error|= sql->append('(');
- error|= sql->append_ulonglong(len);
-
- if (!strcmp(type, "DOUBLE")) {
- error|= sql->append(',');
- // dec must be < len and < 31
- error|= sql->append_ulonglong(min(dec, (min(len, 31) - 1)));
- } else if (dec > 0 && !strcmp(type, "DECIMAL")) {
- error|= sql->append(',');
- // dec must be < len
- error|= sql->append_ulonglong(min(dec, len - 1));
- } // endif dec
-
- error|= sql->append(')');
- } // endif len
-
- if (v == 'U')
- error|= sql->append(" UNSIGNED");
- else if (v == 'Z')
- error|= sql->append(" ZEROFILL");
-
- if (tm)
- error|= sql->append(STRING_WITH_LEN(" NOT NULL"), system_charset_info);
-
- if (dft && *dft) {
- error|= sql->append(" DEFAULT ");
-
- if (!IsTypeNum(typ)) {
- error|= sql->append("'");
- error|= sql->append_for_single_quote(dft, strlen(dft));
- error|= sql->append("'");
- } else
- error|= sql->append(dft);
-
- } // endif dft
-
- if (xtra && *xtra) {
- error|= sql->append(" ");
- error|= sql->append(xtra);
- } // endif rem
-
- if (rem && *rem) {
- error|= sql->append(" COMMENT '");
- error|= sql->append_for_single_quote(rem, strlen(rem));
- error|= sql->append("'");
- } // endif rem
-
- if (flag) {
- error|= sql->append(" FLAG=");
- error|= sql->append_ulonglong(flag);
- } // endif flag
-
- 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)
-{
- KEY *not_used_1;
- uint not_used_2;
- 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, C_ORDINARY_CREATE,
- &not_used_1, &not_used_2, &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<uchar*>(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,
-// char *dsn,
- 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) {
-//if (dsn) {
- 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_for_single_quote(dsn, strlen(dsn));
- 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
-
-// Used to check whether a MYSQL table is created on itself
-static bool CheckSelf(PGLOBAL g, TABLE_SHARE *s, const char *host,
- const char *db, char *tab, const char *src, int port)
-{
- if (src)
- return false;
- else if (host && stricmp(host, "localhost") && strcmp(host, "127.0.0.1"))
- return false;
- else if (db && stricmp(db, s->db.str))
- return false;
- else if (tab && stricmp(tab, s->table_name.str))
- return false;
- else if (port && port != (signed)GetDefaultPort())
- return false;
-
- strcpy(g->Message, "This MySQL table is defined on itself");
- return true;
-} // end of CheckSelf
-
-/**
- @brief
- connect_assisted_discovery() is called when creating a table with no columns.
-
- @details
- 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,
- HA_CREATE_INFO *create_info)
-{
- char v, spc= ',', qch= 0;
- const char *fncn= "?";
- const char *user, *fn, *db, *host, *pwd, *sep, *tbl, *src;
- const char *col, *ocl, *rnk, *pic, *fcl;
- char *tab, *dsn, *shm;
-#if defined(WIN32)
- char *nsp= NULL, *cls= NULL;
-#endif // WIN32
- int port= 0, hdr= 0, mxr __attribute__((unused))= 0, mxe= 0, rc= 0;
- int cop __attribute__((unused)) = 0;
- uint tm, fnc= FNC_NO, supfnc= (FNC_NO | FNC_COL);
- bool bif, ok= false, dbf= false;
- TABTYPE ttp= TAB_UNDEF;
- PQRYRES qrp= NULL;
- PCOLRES crp;
- PCONNECT xp= NULL;
- PGLOBAL g= GetPlug(thd, xp);
- 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;
-
- user= host= pwd= tbl= src= col= ocl= pic= fcl= rnk= dsn= NULL;
-
- // Get the useful create options
- ttp= GetTypeID(topt->type);
- fn= topt->filename;
- tab= (char*)topt->tabname;
- src= topt->srcdef;
- db= topt->dbname;
- fncn= topt->catfunc;
- fnc= GetFuncID(fncn);
- sep= topt->separator;
- spc= (!sep || !strcmp(sep, "\\t")) ? '\t' : *sep;
- qch= topt->qchar ? *topt->qchar : (signed)topt->quoted >= 0 ? '"' : 0;
- hdr= (int)topt->header;
- tbl= topt->tablist;
- col= topt->colist;
-
- if (topt->oplist) {
- host= GetListOption(g, "host", topt->oplist, "localhost");
- user= GetListOption(g, "user", topt->oplist, "root");
- // Default value db can come from the DBNAME=xxx option.
- db= GetListOption(g, "database", topt->oplist, db);
- col= GetListOption(g, "colist", topt->oplist, col);
- ocl= GetListOption(g, "occurcol", topt->oplist, NULL);
- pic= GetListOption(g, "pivotcol", topt->oplist, NULL);
- fcl= GetListOption(g, "fnccol", topt->oplist, NULL);
- rnk= GetListOption(g, "rankcol", topt->oplist, NULL);
- pwd= GetListOption(g, "password", topt->oplist);
-#if defined(WIN32)
- nsp= GetListOption(g, "namespace", topt->oplist);
- cls= GetListOption(g, "class", topt->oplist);
-#endif // WIN32
- port= atoi(GetListOption(g, "port", topt->oplist, "0"));
- mxr= atoi(GetListOption(g,"maxres", topt->oplist, "0"));
- mxe= atoi(GetListOption(g,"maxerr", topt->oplist, "0"));
-#if defined(PROMPT_OK)
- cop= atoi(GetListOption(g, "checkdsn", topt->oplist, "0"));
-#endif // PROMPT_OK
- } else {
- host= "localhost";
- user= "root";
- } // endif option_list
-
- if (!(shm= (char*)db))
- db= table_s->db.str; // Default value
-
- // Check table type
- if (ttp == TAB_UNDEF) {
- topt->type= (src) ? "MYSQL" : (tab) ? "PROXY" : "DOS";
- ttp= GetTypeID(topt->type);
- sprintf(g->Message, "No table_type. Was set to %s", topt->type);
- push_warning(thd, 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));
- return HA_ERR_INTERNAL_ERROR;
- } // endif ttp
-
- if (!tab) {
- if (ttp == TAB_TBL) {
- // Make tab the first table of the list
- char *p;
-
- if (!tbl) {
- strcpy(g->Message, "Missing table list");
- my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
- return HA_ERR_INTERNAL_ERROR;
- } // endif tbl
-
- tab= (char*)PlugSubAlloc(g, NULL, strlen(tbl) + 1);
- strcpy(tab, tbl);
-
- if ((p= strchr(tab, ',')))
- *p= 0;
-
- if ((p=strchr(tab, '.'))) {
- *p= 0;
- db= tab;
- tab= p + 1;
- } // endif p
-
- } else if (ttp != TAB_ODBC || !(fnc & (FNC_TABLE | FNC_COL)))
- tab= table_s->table_name.str; // Default value
-
-#if defined(NEW_WAY)
-// add_option(thd, create_info, "tabname", tab);
-#endif // NEW_WAY
- } // endif tab
-
- switch (ttp) {
-#if defined(ODBC_SUPPORT)
- case TAB_ODBC:
- dsn= create_info->connect_string.str;
-
- if (fnc & (FNC_DSN | FNC_DRIVER)) {
- ok= true;
-#if defined(PROMPT_OK)
- } else if (!stricmp(thd->main_security_ctx.host, "localhost")
- && cop == 1) {
- if ((dsn = ODBCCheckConnection(g, dsn, cop)) != NULL) {
- thd->make_lex_string(&create_info->connect_string, dsn, strlen(dsn));
- ok= true;
- } // endif dsn
-#endif // PROMPT_OK
-
- } else if (!dsn)
- sprintf(g->Message, "Missing %s connection string", topt->type);
- else
- ok= true;
-
- supfnc |= (FNC_TABLE | FNC_DSN | FNC_DRIVER);
- break;
-#endif // ODBC_SUPPORT
- case TAB_DBF:
- dbf= true;
- // Passthru
- case TAB_CSV:
- if (!fn && fnc != FNC_NO)
- sprintf(g->Message, "Missing %s file name", topt->type);
- else
- ok= true;
-
- break;
-#if defined(MYSQL_SUPPORT)
- case TAB_MYSQL:
- ok= true;
-
- if (create_info->connect_string.str) {
- int len= create_info->connect_string.length;
- PMYDEF mydef= new(g) MYSQLDEF();
- PDBUSER dup= PlgGetUser(g);
- PCATLG cat= (dup) ? dup->Catalog : NULL;
-
- dsn= (char*)PlugSubAlloc(g, NULL, len + 1);
- strncpy(dsn, create_info->connect_string.str, len);
- dsn[len]= 0;
- mydef->SetName(create_info->alias);
- mydef->SetCat(cat);
-
- if (!mydef->ParseURL(g, dsn, false)) {
- if (mydef->GetHostname())
- host= mydef->GetHostname();
-
- if (mydef->GetUsername())
- user= mydef->GetUsername();
-
- if (mydef->GetPassword())
- pwd= mydef->GetPassword();
-
- if (mydef->GetDatabase())
- db= mydef->GetDatabase();
-
- if (mydef->GetTabname())
- tab= mydef->GetTabname();
-
- if (mydef->GetPortnumber())
- port= mydef->GetPortnumber();
-
- } else
- ok= false;
-
- } else if (!user)
- user= "root";
-
- if (CheckSelf(g, table_s, host, db, tab, src, port))
- ok= false;
-
- break;
-#endif // MYSQL_SUPPORT
-#if defined(WIN32)
- case TAB_WMI:
- ok= true;
- break;
-#endif // WIN32
- case TAB_PIVOT:
- supfnc= FNC_NO;
- case TAB_PRX:
- case TAB_TBL:
- case TAB_XCL:
- case TAB_OCCUR:
- if (!src && !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;
- 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);
- break;
- } // endif ttp
-
- // Check for supported catalog function
- if (ok && !(supfnc & fnc)) {
- sprintf(g->Message, "Unsupported catalog function %s for table type %s",
- fncn, topt->type);
- ok= false;
- } // endif supfnc
-
- if (src && fnc != FNC_NO) {
- strcpy(g->Message, "Cannot make catalog table from srcdef");
- ok= false;
- } // endif src
-
- if (ok) {
- char *cnm, *rem, *dft, *xtra;
- int i, len, prec, dec, typ, flg;
- PDBUSER dup= PlgGetUser(g);
- PCATLG cat= (dup) ? dup->Catalog : NULL;
-
- if (cat)
- cat->SetDataPath(g, table_s->db.str);
- else
- return HA_ERR_INTERNAL_ERROR; // Should never happen
-
- if (src && ttp != TAB_PIVOT && ttp != TAB_ODBC) {
- qrp= SrcColumns(g, host, db, user, pwd, src, port);
-
- if (qrp && ttp == TAB_OCCUR)
- if (OcrSrcCols(g, qrp, col, ocl, rnk)) {
- my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
- return HA_ERR_INTERNAL_ERROR;
- } // endif OcrSrcCols
-
- } else switch (ttp) {
- case TAB_DBF:
- qrp= DBFColumns(g, fn, fnc == FNC_COL);
- break;
-#if defined(ODBC_SUPPORT)
- case TAB_ODBC:
- switch (fnc) {
- case FNC_NO:
- case FNC_COL:
- if (src) {
- qrp= ODBCSrcCols(g, dsn, (char*)src);
- src= NULL; // for next tests
- } else
- qrp= ODBCColumns(g, dsn, shm, tab, NULL, mxr, fnc == FNC_COL);
-
- break;
- case FNC_TABLE:
- qrp= ODBCTables(g, dsn, shm, tab, mxr, true);
- break;
- case FNC_DSN:
- qrp= ODBCDataSources(g, mxr, true);
- break;
- case FNC_DRIVER:
- qrp= ODBCDrivers(g, mxr, true);
- break;
- default:
- sprintf(g->Message, "invalid catfunc %s", fncn);
- break;
- } // endswitch info
-
- break;
-#endif // ODBC_SUPPORT
-#if defined(MYSQL_SUPPORT)
- case TAB_MYSQL:
- qrp= MyColumns(g, host, db, user, pwd, tab,
- NULL, port, fnc == FNC_COL);
- break;
-#endif // MYSQL_SUPPORT
- case TAB_CSV:
- qrp= CSVColumns(g, fn, spc, qch, hdr, mxe, fnc == FNC_COL);
- break;
-#if defined(WIN32)
- case TAB_WMI:
- qrp= WMIColumns(g, nsp, cls, fnc == FNC_COL);
- break;
-#endif // WIN32
- case TAB_PRX:
- case TAB_TBL:
- case TAB_XCL:
- case TAB_OCCUR:
- bif= fnc == FNC_COL;
- qrp= TabColumns(g, thd, db, tab, bif);
-
- if (!qrp && bif && fnc != FNC_COL) // tab is a view
- qrp= MyColumns(g, host, db, user, pwd, tab, NULL, port, false);
-
- if (qrp && ttp == TAB_OCCUR && fnc != FNC_COL)
- if (OcrColumns(g, qrp, col, ocl, rnk)) {
- my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
- return HA_ERR_INTERNAL_ERROR;
- } // endif OcrColumns
-
- break;
- case TAB_PIVOT:
- qrp= PivotColumns(g, tab, src, pic, fcl, host, db, user, pwd, port);
- break;
- case TAB_OEM:
- qrp= OEMColumns(g, topt, tab, (char*)db, fnc == FNC_COL);
- break;
- default:
- strcpy(g->Message, "System error during assisted discovery");
- break;
- } // endswitch ttp
-
- if (!qrp) {
- my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
- return HA_ERR_INTERNAL_ERROR;
- } // endif qrp
-
- if (fnc != FNC_NO || src || ttp == TAB_PIVOT) {
- // Catalog like table
- for (crp= qrp->Colresp; !rc && crp; crp= crp->Next) {
- cnm= encode(g, crp->Name);
- typ= crp->Type;
- len= crp->Length;
- dec= crp->Prec;
- flg= crp->Flag;
- v= crp->Var;
-
- 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,
- NOT_NULL_FLAG, "", flg, dbf, v);
-#else // !NEW_WAY
- // Now add the field
- if (add_field(&sql, cnm, typ, len, dec, NOT_NULL_FLAG,
- NULL, NULL, NULL, flg, dbf, v))
- rc= HA_ERR_OUT_OF_MEM;
-#endif // !NEW_WAY
- } // endfor crp
-
- } else // Not a catalog table
- for (i= 0; !rc && i < qrp->Nblin; i++) {
- typ= len= prec= dec= 0;
- tm= NOT_NULL_FLAG;
- cnm= (char*)"noname";
- dft= xtra= NULL;
-#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) {
- case FLD_NAME:
- cnm= encode(g, crp->Kdata->GetCharValue(i));
- break;
- case FLD_TYPE:
- typ= crp->Kdata->GetIntValue(i);
- v = (crp->Nulls) ? crp->Nulls[i] : 0;
- break;
- case FLD_PREC:
- // PREC must be always before LENGTH
- len= prec= crp->Kdata->GetIntValue(i);
- break;
- case FLD_LENGTH:
- len= crp->Kdata->GetIntValue(i);
- break;
- case FLD_SCALE:
- dec= crp->Kdata->GetIntValue(i);
- break;
- case FLD_NULL:
- if (crp->Kdata->GetIntValue(i))
- tm= 0; // Nullable
-
- break;
- case FLD_REM:
- rem= crp->Kdata->GetCharValue(i);
- break;
-// case FLD_CHARSET:
- // No good because remote table is already translated
-// if (*(csn= crp->Kdata->GetCharValue(i)))
-// cs= get_charset_by_name(csn, 0);
-
-// break;
- case FLD_DEFAULT:
- dft= crp->Kdata->GetCharValue(i);
- break;
- case FLD_EXTRA:
- xtra= crp->Kdata->GetCharValue(i);
- break;
- default:
- break; // Ignore
- } // endswitch Fld
-
-#if defined(ODBC_SUPPORT)
- if (ttp == TAB_ODBC) {
- int plgtyp;
-
- // typ must be PLG type, not SQL type
- if (!(plgtyp= TranslateSQLType(typ, dec, prec, v))) {
- sprintf(g->Message, "Unsupported SQL type %d", typ);
- my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
- return HA_ERR_INTERNAL_ERROR;
- } else
- typ= plgtyp;
-
- switch (typ) {
- case TYPE_DOUBLE:
- // Some data sources do not count dec in length (prec)
- prec += (dec + 2); // To be safe
- case TYPE_DECIM:
- break;
- default:
- dec= 0;
- } // endswitch typ
-
- } // endif ttp
-#endif // ODBC_SUPPORT
-
- // Make the arguments as required by add_fields
- if (typ == TYPE_DATE)
- prec= 0;
- else if (typ == TYPE_DOUBLE)
- prec= len;
-
- // Now add the field
-#if defined(NEW_WAY)
- rc= add_fields(g, thd, &alter_info, cnm, typ, prec, dec,
- tm, rem, 0, dbf, v);
-#else // !NEW_WAY
- if (add_field(&sql, cnm, typ, prec, dec, tm, rem, dft, xtra,
- 0, dbf, v))
- rc= HA_ERR_OUT_OF_MEM;
-#endif // !NEW_WAY
- } // endfor i
-
-#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);
-// rc= init_table_share(thd, table_s, create_info, dsn, &sql);
-#endif // !NEW_WAY
-
- return rc;
- } // endif ok
-
- my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
- return HA_ERR_INTERNAL_ERROR;
-} // end of connect_assisted_discovery
-
-/**
- Get the database name from a qualified table name.
-*/
-char *ha_connect::GetDBfromName(const char *name)
-{
- char *db, dbname[128], tbname[128];
-
- if (filename_to_dbname_and_tablename(name, dbname, sizeof(dbname),
- tbname, sizeof(tbname)))
- *dbname= 0;
-
- if (*dbname) {
- assert(xp && xp->g);
- db= (char*)PlugSubAlloc(xp->g, NULL, strlen(dbname + 1));
- strcpy(db, dbname);
- } else
- db= NULL;
-
- return db;
-} // end of GetDBfromName
-
-
-/**
- @brief
- create() is called to create a database. The variable name will have the name
- of the table.
-
- @details
- When create() is called you do not need to worry about
- opening the table. Also, the .frm file will have already been
- created so adjusting create_info is not necessary. You can overwrite
- the .frm file at this point if you wish to change the table
- definition, but there are no methods currently provided for doing
- so.
-
- Called from handle.cc by ha_create_table().
-
- @note
- Currently we do some checking on the create definitions and stop
- creating if an error is found. We wish we could change the table
- definition such as providing a default table type. However, as said
- above, there are no method to do so.
-
- @see
- ha_create_table() in handle.cc
-*/
-
-int ha_connect::create(const char *name, TABLE *table_arg,
- HA_CREATE_INFO *create_info)
-{
- int rc= RC_OK;
- bool dbf;
- Field* *field;
- Field *fp;
- TABTYPE type;
- TABLE *st= table; // Probably unuseful
- THD *thd= ha_thd();
- xp= GetUser(thd, xp);
- 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)
- htrc("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);
-
- // Check table type
- if (type == TAB_UNDEF) {
- options->type= (options->srcdef) ? "MYSQL" :
- (options->tabname) ? "PROXY" : "DOS";
- type= GetTypeID(options->type);
- sprintf(g->Message, "No table_type. Will be set to %s", options->type);
-
- if (sqlcom == SQLCOM_CREATE_TABLE)
- push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
-
- } else if (type == TAB_NIY) {
- sprintf(g->Message, "Unsupported table type %s", options->type);
- my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
- DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
- } // endif ttp
-
- if (check_privileges(thd, options, GetDBfromName(name)))
- DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
-
- if (options->data_charset) {
- const CHARSET_INFO *data_charset;
-
- if (!(data_charset= get_charset_by_csname(options->data_charset,
- MY_CS_PRIMARY, MYF(0)))) {
- my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), options->data_charset);
- DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
- } // endif charset
-
- if (type == TAB_XML && data_charset != &my_charset_utf8_general_ci) {
- my_printf_error(ER_UNKNOWN_ERROR,
- "DATA_CHARSET='%s' is not supported for TABLE_TYPE=XML",
- MYF(0), options->data_charset);
- DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
- } // endif utf8
-
- } // endif charset
-
- if (!g) {
- rc= HA_ERR_INTERNAL_ERROR;
- DBUG_RETURN(rc);
- } else
- dbf= (GetTypeID(options->type) == TAB_DBF && !options->catfunc);
-
- // Can be null in ALTER TABLE
- if (create_info->alias)
- // Check whether a table is defined on itself
- switch (type) {
- case TAB_PRX:
- case TAB_XCL:
- case TAB_PIVOT:
- case TAB_OCCUR:
- if (options->srcdef) {
- strcpy(g->Message, "Cannot check looping reference");
- push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
- } else if (options->tabname) {
- if (!stricmp(options->tabname, create_info->alias) &&
- (!options->dbname || !stricmp(options->dbname, table_arg->s->db.str))) {
- sprintf(g->Message, "A %s table cannot refer to itself",
- options->type);
- my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
- DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
- } // endif tab
-
- } else {
- strcpy(g->Message, "Missing object table name or definition");
- my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
- DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
- } // endif tabname
-
- case TAB_MYSQL:
- {const char *src= options->srcdef;
- char *host, *db, *tab= (char*)options->tabname;
- int port;
-
- host= GetListOption(g, "host", options->oplist, NULL);
- db= GetListOption(g, "database", options->oplist, NULL);
- port= atoi(GetListOption(g, "port", options->oplist, "0"));
-
- if (create_info->connect_string.str) {
- char *dsn;
- int len= create_info->connect_string.length;
- PMYDEF mydef= new(g) MYSQLDEF();
- PDBUSER dup= PlgGetUser(g);
- PCATLG cat= (dup) ? dup->Catalog : NULL;
-
- dsn= (char*)PlugSubAlloc(g, NULL, len + 1);
- strncpy(dsn, create_info->connect_string.str, len);
- dsn[len]= 0;
- mydef->SetName(create_info->alias);
- mydef->SetCat(cat);
-
- if (!mydef->ParseURL(g, dsn, false)) {
- if (mydef->GetHostname())
- host= mydef->GetHostname();
-
- if (mydef->GetDatabase())
- db= mydef->GetDatabase();
-
- if (mydef->GetTabname())
- tab= mydef->GetTabname();
-
- if (mydef->GetPortnumber())
- port= mydef->GetPortnumber();
-
- } else {
- my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
- DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
- } // endif ParseURL
-
- } // endif connect_string
-
- if (CheckSelf(g, table_arg->s, host, db, tab, src, port)) {
- my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
- DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
- } // endif CheckSelf
-
- }break;
- default: /* do nothing */;
- break;
- } // endswitch ttp
-
- if (type == TAB_XML) {
- bool dom; // True: MS-DOM, False libxml2
- char *xsup= GetListOption(g, "Xmlsup", options->oplist, "*");
-
- // Note that if no support is specified, the default is MS-DOM
- // on Windows and libxml2 otherwise
- switch (*xsup) {
- case '*':
-#if defined(WIN32)
- dom= true;
-#else // !WIN32
- dom= false;
-#endif // !WIN32
- break;
- case 'M':
- case 'D':
- dom= true;
- break;
- default:
- dom= false;
- break;
- } // endswitch xsup
-
-#if !defined(DOMDOC_SUPPORT)
- if (dom) {
- strcpy(g->Message, "MS-DOM not supported by this version");
- xsup= NULL;
- } // endif DomDoc
-#endif // !DOMDOC_SUPPORT
-
-#if !defined(LIBXML2_SUPPORT)
- if (!dom) {
- strcpy(g->Message, "libxml2 not supported by this version");
- xsup= NULL;
- } // endif Libxml2
-#endif // !LIBXML2_SUPPORT
-
- if (!xsup) {
- my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
- rc= HA_ERR_INTERNAL_ERROR;
- DBUG_RETURN(rc);
- } // endif xsup
-
- } // endif type
-
- // Check column types
- for (field= table_arg->field; *field; field++) {
- fp= *field;
-
- if (fp->vcol_info && !fp->stored_in_db)
- continue; // This is a virtual column
-
- if (fp->flags & AUTO_INCREMENT_FLAG) {
- strcpy(g->Message, "Auto_increment is not supported yet");
- my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
- rc= HA_ERR_INTERNAL_ERROR;
- DBUG_RETURN(rc);
- } // endif flags
-
- if (fp->flags & (BLOB_FLAG | ENUM_FLAG | SET_FLAG)) {
- sprintf(g->Message, "Unsupported type for column %s",
- fp->field_name);
- my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
- rc= HA_ERR_INTERNAL_ERROR;
- DBUG_RETURN(rc);
- } // endif flags
-
- switch (fp->type()) {
- case MYSQL_TYPE_SHORT:
- case MYSQL_TYPE_LONG:
- case MYSQL_TYPE_FLOAT:
- case MYSQL_TYPE_DOUBLE:
- case MYSQL_TYPE_TIMESTAMP:
- case MYSQL_TYPE_DATE:
- case MYSQL_TYPE_TIME:
- case MYSQL_TYPE_DATETIME:
- case MYSQL_TYPE_YEAR:
- case MYSQL_TYPE_NEWDATE:
- case MYSQL_TYPE_LONGLONG:
- case MYSQL_TYPE_TINY:
- case MYSQL_TYPE_DECIMAL:
- case MYSQL_TYPE_NEWDECIMAL:
- case MYSQL_TYPE_INT24:
- break; // Ok
- case MYSQL_TYPE_VARCHAR:
- case MYSQL_TYPE_VAR_STRING:
- case MYSQL_TYPE_STRING:
- if (!fp->field_length) {
- sprintf(g->Message, "Unsupported 0 length for column %s",
- fp->field_name);
- rc= HA_ERR_INTERNAL_ERROR;
- my_printf_error(ER_UNKNOWN_ERROR,
- "Unsupported 0 length for column %s",
- MYF(0), fp->field_name);
- DBUG_RETURN(rc);
- } // endif fp
-
- break; // To be checked
- case MYSQL_TYPE_BIT:
- case MYSQL_TYPE_NULL:
- case MYSQL_TYPE_ENUM:
- case MYSQL_TYPE_SET:
- case MYSQL_TYPE_TINY_BLOB:
- case MYSQL_TYPE_MEDIUM_BLOB:
- case MYSQL_TYPE_LONG_BLOB:
- case MYSQL_TYPE_BLOB:
- case MYSQL_TYPE_GEOMETRY:
- default:
-// fprintf(stderr, "Unsupported type column %s\n", fp->field_name);
- sprintf(g->Message, "Unsupported type for column %s",
- fp->field_name);
- rc= HA_ERR_INTERNAL_ERROR;
- my_printf_error(ER_UNKNOWN_ERROR, "Unsupported type for column %s",
- MYF(0), fp->field_name);
- DBUG_RETURN(rc);
- break;
- } // endswitch type
-
- if ((fp)->real_maybe_null() && !IsTypeNullable(type)) {
- my_printf_error(ER_UNKNOWN_ERROR,
- "Table type %s does not support nullable columns",
- MYF(0), options->type);
- DBUG_RETURN(HA_ERR_UNSUPPORTED);
- } // endif !nullable
-
- if (dbf) {
- bool b= false;
-
- if ((b= strlen(fp->field_name) > 10))
- sprintf(g->Message, "DBF: Column name '%s' is too long (max=10)",
- fp->field_name);
- else if ((b= fp->field_length > 255))
- sprintf(g->Message, "DBF: Column length too big for '%s' (max=255)",
- fp->field_name);
-
- if (b) {
- my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
- rc= HA_ERR_INTERNAL_ERROR;
- DBUG_RETURN(rc);
- } // endif b
-
- } // endif dbf
-
- } // endfor field
-
- 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]);
-
- strcat(strcat(buf, "."), lwt);
- sprintf(g->Message, "No file name. Table will use %s", buf);
-
- if (sqlcom == SQLCOM_CREATE_TABLE)
- push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
-
- strcat(strcat(strcpy(dbpath, "./"), table->s->db.str), "/");
- PlugSetPath(fn, buf, dbpath);
-
- 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(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
- } else
- ::close(h);
-
- if (type == TAB_FMT || options->readonly)
- push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0,
- "Congratulation, you just created a read-only void table!");
-
- } // endif
-
- if (xtrace)
- htrc("xchk=%p createas=%d\n", g->Xchk, g->Createas);
-
- // To check whether indices have to be made or remade
- if (!g->Xchk) {
- PIXDEF xdp;
-
- // 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)) {
- PDBUSER dup= PlgGetUser(g);
- PCATLG cat= (dup) ? dup->Catalog : NULL;
-
- if (cat) {
- cat->SetDataPath(g, table_arg->s->db.str);
-
- if ((rc= optimize(table->in_use, NULL))) {
- htrc("Create rc=%d %s\n", rc, g->Message);
- my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
- rc= HA_ERR_INTERNAL_ERROR;
- } else
- CloseTable(g);
-
- } // endif cat
-
- } else {
- sprintf(g->Message, "Table type %s is not indexable", options->type);
- my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
- rc= HA_ERR_UNSUPPORTED;
- } // endif Indexable
-
- } // 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)) {
- g->Xchk= NULL;
- sprintf(g->Message, "Table type %s is not indexable", options->type);
- my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
- rc= HA_ERR_INTERNAL_ERROR;
- } else {
- xcp->newpix= xdp;
- xcp->newsep= GetBooleanOption("Sepindex", false);
- } // endif Indexable
-
- } else if (!xcp->oldpix)
- g->Xchk= NULL;
-
- if (xtrace && g->Xchk)
- htrc("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
-
-// Called by SameString and NoFieldOptionChange
-bool ha_connect::CheckString(const char *str1, const char *str2)
-{
- bool 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 CheckString
-
-/**
- check whether a string option have changed
- */
-bool ha_connect::SameString(TABLE *tab, char *opn)
-{
- char *str1, *str2;
-
- tshp= tab->s; // The altered table
- str1= GetStringOption(opn);
- tshp= NULL;
- str2= GetStringOption(opn);
- return CheckString(str1, str2);
-} // end of SameString
-
-/**
- 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 whether a field option have changed
- */
-bool ha_connect::NoFieldOptionChange(TABLE *tab)
-{
- bool rc= true;
- ha_field_option_struct *fop1, *fop2;
- Field* *fld1= table->s->field;
- Field* *fld2= tab->s->field;
-
- for (; rc && *fld1 && *fld2; fld1++, fld2++) {
- fop1= (*fld1)->option_struct;
- fop2= (*fld2)->option_struct;
-
- rc= (fop1->offset == fop2->offset &&
- fop1->fldlen == fop2->fldlen &&
- CheckString(fop1->dateformat, fop2->dateformat) &&
- CheckString(fop1->fieldformat, fop2->fieldformat) &&
- CheckString(fop1->special, fop2->special));
- } // endfor fld
-
- return rc;
-} // end of NoFieldOptionChange
-
- /**
- 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 ||
- !SameString(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)
- htrc(
- "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 (!SameString(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 (NoFieldOptionChange(altered_table) &&
- 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_ALTER_OPERATION_NOT_SUPPORTED,
- "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
- if new and old definition are compatible
-
- @details If there are no other explicit signs like changed number of
- fields this function will be called by compare_tables()
- (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)
-{
- DBUG_ENTER("ha_connect::check_if_incompatible_data");
- // TO DO: really implement and check it.
- 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
-
-/****************************************************************************
- * CONNECT MRR implementation: use DS-MRR
- This is just copied from myisam
- ***************************************************************************/
-
-int ha_connect::multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param,
- uint n_ranges, uint mode,
- HANDLER_BUFFER *buf)
-{
- return ds_mrr.dsmrr_init(this, seq, seq_init_param, n_ranges, mode, buf);
-} // end of multi_range_read_init
-
-int ha_connect::multi_range_read_next(range_id_t *range_info)
-{
- return ds_mrr.dsmrr_next(range_info);
-} // end of multi_range_read_next
-
-ha_rows ha_connect::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
- void *seq_init_param,
- uint n_ranges, uint *bufsz,
- uint *flags, Cost_estimate *cost)
-{
- /*
- This call is here because there is no location where this->table would
- already be known.
- TODO: consider moving it into some per-query initialization call.
- */
- ds_mrr.init(this, table);
-
- // MMR is implemented for "local" file based tables only
- if (!IsFileType(GetRealType(GetTableOptionStruct(table))))
- *flags|= HA_MRR_USE_DEFAULT_IMPL;
-
- ha_rows rows= ds_mrr.dsmrr_info_const(keyno, seq, seq_init_param, n_ranges,
- bufsz, flags, cost);
- xp->g->Mrr= !(*flags & HA_MRR_USE_DEFAULT_IMPL);
- return rows;
-} // end of multi_range_read_info_const
-
-ha_rows ha_connect::multi_range_read_info(uint keyno, uint n_ranges, uint keys,
- uint key_parts, uint *bufsz,
- uint *flags, Cost_estimate *cost)
-{
- ds_mrr.init(this, table);
-
- // MMR is implemented for "local" file based tables only
- if (!IsFileType(GetRealType(GetTableOptionStruct(table))))
- *flags|= HA_MRR_USE_DEFAULT_IMPL;
-
- ha_rows rows= ds_mrr.dsmrr_info(keyno, n_ranges, keys, key_parts, bufsz,
- flags, cost);
- xp->g->Mrr= !(*flags & HA_MRR_USE_DEFAULT_IMPL);
- return rows;
-} // end of multi_range_read_info
-
-
-int ha_connect::multi_range_read_explain_info(uint mrr_mode, char *str,
- size_t size)
-{
- return ds_mrr.dsmrr_explain_info(mrr_mode, str, size);
-} // end of multi_range_read_explain_info
-
-/* CONNECT MRR implementation ends */
-
-#if 0
-// Does this make sens for CONNECT?
-Item *ha_connect::idx_cond_push(uint keyno_arg, Item* idx_cond_arg)
-{
- pushed_idx_cond_keyno= keyno_arg;
- pushed_idx_cond= idx_cond_arg;
- in_range_check_pushed_down= TRUE;
- if (active_index == pushed_idx_cond_keyno)
- mi_set_index_cond_func(file, handler_index_cond_check, this);
- return NULL;
-}
-#endif // 0
-
-
-struct st_mysql_storage_engine connect_storage_engine=
-{ MYSQL_HANDLERTON_INTERFACE_VERSION };
-
-static MYSQL_SYSVAR_INT(xtrace, xtrace,
- PLUGIN_VAR_RQCMDARG, "Console trace value.",
- NULL, update_connect_xtrace, 0, 0, INT_MAX, 1);
-
-static struct st_mysql_sys_var* connect_system_variables[]= {
- MYSQL_SYSVAR(xtrace),
- NULL
-};
-
-maria_declare_plugin(connect)
-{
- MYSQL_STORAGE_ENGINE_PLUGIN,
- &connect_storage_engine,
- "CONNECT",
- "Olivier Bertrand",
- "Management of External Data (SQL/MED), including many file formats",
- PLUGIN_LICENSE_GPL,
- connect_init_func, /* Plugin Init */
- connect_done_func, /* Plugin Deinit */
- 0x0103, /* version number (1.03) */
- NULL, /* status variables */
- connect_system_variables, /* system variables */
- "1.03", /* string version */
- MariaDB_PLUGIN_MATURITY_BETA /* maturity */
-}
-maria_declare_plugin_end;
+ha_create_table_option connect_index_option_list[]=
+{
+ HA_IOPTION_BOOL("DYN", kindx, 0),
+ HA_IOPTION_BOOL("MAPPED", mapped, 0),
+};
+
+/***********************************************************************/
+/* Push G->Message as a MySQL warning. */
+/***********************************************************************/
+bool PushWarning(PGLOBAL g, PTDBASE tdbp, int level)
+{
+ PHC phc;
+ THD *thd;
+ MYCAT *cat= (MYCAT*)tdbp->GetDef()->GetCat();
+
+ if (!cat || !(phc= cat->GetHandler()) || !phc->GetTable() ||
+ !(thd= (phc->GetTable())->in_use))
+ return true;
+
+ PushWarning(g, thd, level);
+ return false;
+} // end of PushWarning
+
+void PushWarning(PGLOBAL g, THD *thd, int level)
+ {
+ if (thd) {
+ Sql_condition::enum_warning_level wlvl;
+
+ wlvl= (Sql_condition::enum_warning_level)level;
+ push_warning(thd, wlvl, 0, g->Message);
+ } else
+ htrc("%s\n", g->Message);
+
+ } // end of PushWarning
+
+#ifdef HAVE_PSI_INTERFACE
+static PSI_mutex_key con_key_mutex_CONNECT_SHARE_mutex;
+
+static PSI_mutex_info all_connect_mutexes[]=
+{
+ { &con_key_mutex_CONNECT_SHARE_mutex, "CONNECT_SHARE::mutex", 0}
+};
+
+static void init_connect_psi_keys()
+{
+ const char* category= "connect";
+ int count;
+
+ if (PSI_server == NULL)
+ return;
+
+ count= array_elements(all_connect_mutexes);
+ PSI_server->register_mutex(category, all_connect_mutexes, count);
+}
+#else
+static void init_connect_psi_keys() {}
+#endif
+
+
+DllExport LPCSTR PlugSetPath(LPSTR to, LPCSTR name, LPCSTR dir)
+{
+ const char *res= PlugSetPath(to, mysql_data_home, name, dir);
+ return res;
+}
+
+
+/**
+ @brief
+ If frm_error() is called then we will use this to determine
+ the file extensions that exist for the storage engine. This is also
+ used by the default rename_table and delete_table method in
+ handler.cc.
+
+ For engines that have two file name extentions (separate meta/index file
+ and data file), the order of elements is relevant. First element of engine
+ file name extentions array should be meta/index file extention. Second
+ element - data file extention. This order is assumed by
+ prepare_for_repair() when REPAIR TABLE ... USE_FRM is issued.
+
+ @see
+ rename_table method in handler.cc and
+ delete_table method in handler.cc
+*/
+static const char *ha_connect_exts[]= {
+ ".dos", ".fix", ".csv", ".bin", ".fmt", ".dbf", ".xml", ".ini", ".vec",
+ ".dnx", ".fnx", ".bnx", ".vnx", ".dbx", ".dop", ".fop", ".bop", ".vop",
+ NULL};
+
+/**
+ @brief
+ Plugin initialization
+*/
+static int connect_init_func(void *p)
+{
+ DBUG_ENTER("connect_init_func");
+
+ sql_print_information("CONNECT: %s", version);
+
+ // xtrace is now a system variable
+ trace= xtrace;
+
+#ifdef LIBXML2_SUPPORT
+ XmlInitParserLib();
+#endif // LIBXML2_SUPPORT
+
+ init_connect_psi_keys();
+
+ connect_hton= (handlerton *)p;
+ connect_hton->state= SHOW_OPTION_YES;
+ connect_hton->create= connect_create_handler;
+ connect_hton->flags= HTON_TEMPORARY_NOT_SUPPORTED | HTON_NO_PARTITION;
+ connect_hton->table_options= connect_table_option_list;
+ connect_hton->field_options= connect_field_option_list;
+ connect_hton->tablefile_extensions= ha_connect_exts;
+ connect_hton->discover_table_structure= connect_assisted_discovery;
+
+ if (xtrace)
+ sql_print_information("connect_init: hton=%p", p);
+
+ DTVAL::SetTimeShift(); // Initialize time zone shift once for all
+ DBUG_RETURN(0);
+}
+
+
+/**
+ @brief
+ Plugin clean up
+*/
+static int connect_done_func(void *p)
+{
+ int error= 0;
+ PCONNECT pc, pn;
+ DBUG_ENTER("connect_done_func");
+
+#ifdef LIBXML2_SUPPORT
+ XmlCleanupParserLib();
+#endif // LIBXML2_SUPPORT
+
+#if !defined(WIN32)
+//PROFILE_End(); Causes signal 11
+#endif // !WIN32
+
+ for (pc= user_connect::to_users; pc; pc= pn) {
+ if (pc->g)
+ PlugCleanup(pc->g, true);
+
+ pn= pc->next;
+ delete pc;
+ } // endfor pc
+
+ DBUG_RETURN(error);
+}
+
+
+/**
+ @brief
+ Example of simple lock controls. The "share" it creates is a
+ structure we will pass to each example handler. Do you have to have
+ one of these? Well, you have pieces that are used for locking, and
+ they are needed to function.
+*/
+
+CONNECT_SHARE *ha_connect::get_share()
+{
+ CONNECT_SHARE *tmp_share;
+ lock_shared_ha_data();
+ if (!(tmp_share= static_cast<CONNECT_SHARE*>(get_ha_share_ptr())))
+ {
+ tmp_share= new CONNECT_SHARE;
+ if (!tmp_share)
+ goto err;
+ mysql_mutex_init(con_key_mutex_CONNECT_SHARE_mutex,
+ &tmp_share->mutex, MY_MUTEX_INIT_FAST);
+ set_ha_share_ptr(static_cast<Handler_share*>(tmp_share));
+ }
+err:
+ unlock_shared_ha_data();
+ return tmp_share;
+}
+
+
+static handler* connect_create_handler(handlerton *hton,
+ TABLE_SHARE *table,
+ MEM_ROOT *mem_root)
+{
+ handler *h= new (mem_root) ha_connect(hton, table);
+
+ if (xtrace)
+ htrc("New CONNECT %p, table: %s\n",
+ h, table ? table->table_name.str : "<null>");
+
+ return h;
+} // end of connect_create_handler
+
+/****************************************************************************/
+/* ha_connect constructor. */
+/****************************************************************************/
+ha_connect::ha_connect(handlerton *hton, TABLE_SHARE *table_arg)
+ :handler(hton, table_arg)
+{
+ hnum= ++num;
+ xp= (table) ? GetUser(ha_thd(), NULL) : NULL;
+ if (xp)
+ xp->SetHandler(this);
+ tdbp= NULL;
+ sdvalin= NULL;
+ sdvalout= NULL;
+ xmod= MODE_ANY;
+ istable= false;
+//*tname= '\0';
+ bzero((char*) &xinfo, sizeof(XINFO));
+ valid_info= false;
+ valid_query_id= 0;
+ creat_query_id= (table && table->in_use) ? table->in_use->query_id : 0;
+ stop= false;
+ alter= false;
+ mrr= false;
+ indexing= -1;
+ locked= 0;
+ data_file_name= NULL;
+ index_file_name= NULL;
+ enable_activate_all_index= 0;
+ int_table_flags= (HA_NO_TRANSACTIONS | HA_NO_PREFIX_CHAR_KEYS);
+ ref_length= sizeof(int);
+ share= NULL;
+ tshp= NULL;
+} // end of ha_connect constructor
+
+
+/****************************************************************************/
+/* ha_connect destructor. */
+/****************************************************************************/
+ha_connect::~ha_connect(void)
+{
+ if (xtrace)
+ htrc("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;
+
+ xp->count--;
+
+ for (p= user_connect::to_users; p; p= p->next)
+ if (p == xp)
+ break;
+
+ if (p && !p->count) {
+ if (p->next)
+ p->next->previous= p->previous;
+
+ if (p->previous)
+ p->previous->next= p->next;
+ else
+ user_connect::to_users= p->next;
+
+ } // endif p
+
+ if (!xp->count) {
+ PlugCleanup(xp->g, true);
+ delete xp;
+ } // endif count
+
+ } // endif xp
+
+} // end of ha_connect destructor
+
+
+/****************************************************************************/
+/* Get a pointer to the user of this handler. */
+/****************************************************************************/
+static PCONNECT GetUser(THD *thd, PCONNECT xp)
+{
+ const char *dbn= NULL;
+
+ if (!thd)
+ return NULL;
+
+ if (xp && thd == xp->thdp)
+ return xp;
+
+ for (xp= user_connect::to_users; xp; xp= xp->next)
+ if (thd == xp->thdp)
+ break;
+
+ if (!xp) {
+ xp= new user_connect(thd, dbn);
+
+ if (xp->user_init()) {
+ delete xp;
+ xp= NULL;
+ } // endif user_init
+
+ } else
+ xp->count++;
+
+ return xp;
+} // end of GetUser
+
+
+/****************************************************************************/
+/* Get the global pointer of the user of this handler. */
+/****************************************************************************/
+static PGLOBAL GetPlug(THD *thd, PCONNECT& lxp)
+{
+ lxp= GetUser(thd, 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_CAN_VIRTUAL_COLUMNS | HA_REC_NOT_IN_SEQ |
+ HA_NO_AUTO_INCREMENT | HA_NO_PREFIX_CHAR_KEYS |
+ HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE |
+ HA_PARTIAL_COLUMN_READ |
+// HA_NULL_IN_KEY | not implemented yet
+// HA_FAST_KEY_READ | causes error when sorting (???)
+ HA_NO_TRANSACTIONS | HA_DUPLICATE_KEY_NOT_IN_ORDER |
+ HA_NO_BLOBS | 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;
+
+ if (IsExactType(type))
+ flags|= (HA_HAS_RECORDS | HA_STATS_RECORDS_IS_EXACT);
+
+ // 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. */
+/****************************************************************************/
+char *GetListOption(PGLOBAL g, const char *opname,
+ const char *oplist, const char *def)
+{
+ char key[16], val[256];
+ char *pk, *pv, *pn;
+ char *opval= (char*) def;
+ int n;
+
+ for (pk= (char*)oplist; pk; pk= ++pn) {
+ pn= strchr(pk, ',');
+ pv= strchr(pk, '=');
+
+ if (pv && (!pn || pv < pn)) {
+ n= pv - pk;
+ memcpy(key, pk, n);
+ key[n]= 0;
+ pv++;
+
+ if (pn) {
+ n= pn - pv;
+ memcpy(val, pv, n);
+ val[n]= 0;
+ } else
+ strcpy(val, pv);
+
+ } else {
+ if (pn) {
+ n= min(pn - pk, 15);
+ memcpy(key, pk, n);
+ key[n]= 0;
+ } else
+ strcpy(key, pk);
+
+ val[0]= 0;
+ } // endif pv
+
+ if (!stricmp(opname, key)) {
+ opval= (char*)PlugSubAlloc(g, NULL, strlen(val) + 1);
+ strcpy(opval, val);
+ break;
+ } else if (!pn)
+ break;
+
+ } // endfor pk
+
+ return opval;
+} // end of GetListOption
+
+/****************************************************************************/
+/* Return the table option structure. */
+/****************************************************************************/
+PTOS ha_connect::GetTableOptionStruct(TABLE *tab)
+{
+ return (tshp) ? tshp->option_struct :
+ (tab) ? tab->s->option_struct : NULL;
+} // end of GetTableOptionStruct
+
+/****************************************************************************/
+/* Return the value of a string option or NULL if not specified. */
+/****************************************************************************/
+char *ha_connect::GetStringOption(char *opname, char *sdef)
+{
+ char *opval= NULL;
+ PTOS options= GetTableOptionStruct(table);
+
+ if (!options)
+ ;
+ else if (!stricmp(opname, "Type"))
+ opval= (char*)options->type;
+ else if (!stricmp(opname, "Filename"))
+ opval= (char*)options->filename;
+ else if (!stricmp(opname, "Optname"))
+ opval= (char*)options->optname;
+ else if (!stricmp(opname, "Tabname"))
+ opval= (char*)options->tabname;
+ else if (!stricmp(opname, "Tablist"))
+ opval= (char*)options->tablist;
+ else if (!stricmp(opname, "Database") ||
+ !stricmp(opname, "DBname"))
+ opval= (char*)options->dbname;
+ else if (!stricmp(opname, "Separator"))
+ opval= (char*)options->separator;
+ else if (!stricmp(opname, "Connect"))
+ opval= (tshp) ? tshp->connect_string.str : table->s->connect_string.str;
+ else if (!stricmp(opname, "Qchar"))
+ opval= (char*)options->qchar;
+ else if (!stricmp(opname, "Module"))
+ opval= (char*)options->module;
+ else if (!stricmp(opname, "Subtype"))
+ opval= (char*)options->subtype;
+ else if (!stricmp(opname, "Catfunc"))
+ opval= (char*)options->catfunc;
+ else if (!stricmp(opname, "Srcdef"))
+ opval= (char*)options->srcdef;
+ else if (!stricmp(opname, "Colist"))
+ opval= (char*)options->colist;
+ else if (!stricmp(opname, "Data_charset"))
+ opval= (char*)options->data_charset;
+ else if (!stricmp(opname, "Query_String"))
+ opval= thd_query_string(table->in_use)->str;
+
+ if (!opval && options && options->oplist)
+ opval= GetListOption(xp->g, opname, options->oplist);
+
+ if (!opval) {
+ if (sdef && !strcmp(sdef, "*")) {
+ // Return the handler default value
+ if (!stricmp(opname, "Dbname") || !stricmp(opname, "Database"))
+ opval= (char*)GetDBName(NULL); // Current database
+ else if (!stricmp(opname, "Type")) // Default type
+ opval= (!options) ? NULL :
+ (options->srcdef) ? (char*)"MYSQL" :
+ (options->tabname) ? (char*)"PROXY" : (char*)"DOS";
+ else if (!stricmp(opname, "User")) // Connected user
+ opval= (char *) "root";
+ else if (!stricmp(opname, "Host")) // Connected user host
+ opval= (char *) "localhost";
+ else
+ opval= sdef; // Caller default
+
+ } else
+ opval= sdef; // Caller default
+
+ } // endif !opval
+
+ return opval;
+} // end of GetStringOption
+
+/****************************************************************************/
+/* Return the value of a Boolean option or bdef if not specified. */
+/****************************************************************************/
+bool ha_connect::GetBooleanOption(char *opname, bool bdef)
+{
+ bool opval= bdef;
+ char *pv;
+ PTOS options= GetTableOptionStruct(table);
+
+ if (!stricmp(opname, "View"))
+ opval= (tshp) ? tshp->is_view : table->s->is_view;
+ else if (!options)
+ ;
+ else if (!stricmp(opname, "Mapped"))
+ opval= options->mapped;
+ else if (!stricmp(opname, "Huge"))
+ opval= options->huge;
+//else if (!stricmp(opname, "Compressed"))
+// opval= options->compressed;
+ else if (!stricmp(opname, "Split"))
+ opval= options->split;
+ else if (!stricmp(opname, "Readonly"))
+ opval= options->readonly;
+ else if (!stricmp(opname, "SepIndex"))
+ opval= options->sepindex;
+ else if (options->oplist)
+ if ((pv= GetListOption(xp->g, opname, options->oplist)))
+ opval= (!*pv || *pv == 'y' || *pv == 'Y' || atoi(pv) != 0);
+
+ return opval;
+} // end of GetBooleanOption
+
+/****************************************************************************/
+/* Set the value of the opname option (does not work for oplist options) */
+/* Currently used only to set the Sepindex value. */
+/****************************************************************************/
+bool ha_connect::SetBooleanOption(char *opname, bool b)
+{
+ PTOS options= GetTableOptionStruct(table);
+
+ if (!options)
+ return true;
+
+ if (!stricmp(opname, "SepIndex"))
+ options->sepindex= b;
+ else
+ return true;
+
+ return false;
+} // end of SetBooleanOption
+
+/****************************************************************************/
+/* Return the value of an integer option or NO_IVAL if not specified. */
+/****************************************************************************/
+int ha_connect::GetIntegerOption(char *opname)
+{
+ ulonglong opval= NO_IVAL;
+ char *pv;
+ PTOS options= GetTableOptionStruct(table);
+
+ if (!options)
+ ;
+ else if (!stricmp(opname, "Lrecl"))
+ opval= options->lrecl;
+ else if (!stricmp(opname, "Elements"))
+ opval= options->elements;
+ else if (!stricmp(opname, "Estimate"))
+// opval= options->estimate;
+ opval= (int)table->s->max_rows;
+ else if (!stricmp(opname, "Avglen"))
+ opval= (int)table->s->avg_row_length;
+ else if (!stricmp(opname, "Multiple"))
+ opval= options->multiple;
+ else if (!stricmp(opname, "Header"))
+ opval= options->header;
+ else if (!stricmp(opname, "Quoted"))
+ opval= options->quoted;
+ else if (!stricmp(opname, "Ending"))
+ opval= options->ending;
+ else if (!stricmp(opname, "Compressed"))
+ opval= (options->compressed);
+
+ if (opval == (ulonglong)NO_IVAL && options && options->oplist)
+ if ((pv= GetListOption(xp->g, opname, options->oplist)))
+ opval= CharToNumber(pv, strlen(pv), ULONGLONG_MAX, true);
+
+ return (int)opval;
+} // end of GetIntegerOption
+
+/****************************************************************************/
+/* Set the value of the opname option (does not work for oplist options) */
+/* Currently used only to set the Lrecl value. */
+/****************************************************************************/
+bool ha_connect::SetIntegerOption(char *opname, int n)
+{
+ PTOS options= GetTableOptionStruct(table);
+
+ if (!options)
+ return true;
+
+ if (!stricmp(opname, "Lrecl"))
+ options->lrecl= n;
+ else if (!stricmp(opname, "Elements"))
+ options->elements= n;
+//else if (!stricmp(opname, "Estimate"))
+// options->estimate= n;
+ else if (!stricmp(opname, "Multiple"))
+ options->multiple= n;
+ else if (!stricmp(opname, "Header"))
+ options->header= n;
+ else if (!stricmp(opname, "Quoted"))
+ options->quoted= n;
+ else if (!stricmp(opname, "Ending"))
+ options->ending= n;
+ else if (!stricmp(opname, "Compressed"))
+ options->compressed= n;
+ else
+ return true;
+//else if (options->oplist)
+// SetListOption(opname, options->oplist, n);
+
+ return false;
+} // end of SetIntegerOption
+
+/****************************************************************************/
+/* Return a field option structure. */
+/****************************************************************************/
+PFOS ha_connect::GetFieldOptionStruct(Field *fdp)
+{
+ return fdp->option_struct;
+} // end of GetFildOptionStruct
+
+/****************************************************************************/
+/* Returns the column description structure used to make the column. */
+/****************************************************************************/
+void *ha_connect::GetColumnOption(PGLOBAL g, void *field, PCOLINFO pcf)
+{
+ const char *cp;
+ char *chset, v;
+ ha_field_option_struct *fop;
+ Field* fp;
+ Field* *fldp;
+
+ // Double test to be on the safe side
+ if (!table)
+ return NULL;
+
+ // Find the column to describe
+ if (field) {
+ fldp= (Field**)field;
+ fldp++;
+ } else
+ fldp= (tshp) ? tshp->field : table->field;
+
+ if (!fldp || !(fp= *fldp))
+ return NULL;
+
+ // Get the CONNECT field options structure
+ fop= GetFieldOptionStruct(fp);
+ pcf->Flags= 0;
+
+ // Now get column information
+ pcf->Name= (char*)fp->field_name;
+
+ if (fop && fop->special) {
+ pcf->Fieldfmt= (char*)fop->special;
+ pcf->Flags= U_SPECIAL;
+ return fldp;
+ } // endif special
+
+ pcf->Scale= 0;
+ pcf->Opt= (fop) ? (int)fop->opt : 0;
+
+ if ((pcf->Length= fp->field_length) < 0)
+ pcf->Length= 256; // BLOB?
+
+ pcf->Precision= pcf->Length;
+
+ if (fop) {
+ pcf->Offset= (int)fop->offset;
+ pcf->Freq= (int)fop->freq;
+ pcf->Datefmt= (char*)fop->dateformat;
+ pcf->Fieldfmt= (char*)fop->fieldformat;
+ } else {
+ pcf->Offset= -1;
+ pcf->Freq= 0;
+ pcf->Datefmt= NULL;
+ pcf->Fieldfmt= NULL;
+ } // endif fop
+
+ chset = (char *)fp->charset()->name;
+ v = (!strcmp(chset, "binary")) ? 'B' : 0;
+
+ switch (fp->type()) {
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_VARCHAR:
+ case MYSQL_TYPE_VAR_STRING:
+ pcf->Flags |= U_VAR;
+ /* no break */
+ default:
+ pcf->Type= MYSQLtoPLG(fp->type(), &v);
+ break;
+ } // endswitch SQL type
+
+ switch (pcf->Type) {
+ case TYPE_STRING:
+ // Do something for case
+ cp= fp->charset()->name;
+
+ // Find if collation name ends by _ci
+ if (!strcmp(cp + strlen(cp) - 3, "_ci")) {
+ pcf->Scale= 1; // Case insensitive
+ pcf->Opt= 0; // Prevent index opt until it is safe
+ } // endif ci
+
+ break;
+ case TYPE_DOUBLE:
+ pcf->Scale= max(min(fp->decimals(), ((unsigned)pcf->Length - 2)), 0);
+ break;
+ case TYPE_DECIM:
+ pcf->Precision= ((Field_new_decimal*)fp)->precision;
+ pcf->Scale= fp->decimals();
+ break;
+ case TYPE_DATE:
+ // Field_length is only used for DATE columns
+ if (fop && fop->fldlen)
+ pcf->Length= (int)fop->fldlen;
+ else {
+ int len;
+
+ if (pcf->Datefmt) {
+ // Find the (max) length produced by the date format
+ char buf[256];
+ PGLOBAL g= GetPlug(table->in_use, xp);
+ PDTP pdtp= MakeDateFormat(g, pcf->Datefmt, false, true, 0);
+ struct tm datm;
+ bzero(&datm, sizeof(datm));
+ datm.tm_mday= 12;
+ datm.tm_mon= 11;
+ datm.tm_year= 112;
+ len= strftime(buf, 256, pdtp->OutFmt, &datm);
+ } else
+ len= 0;
+
+ // 11 is for signed numeric representation of the date
+ pcf->Length= (len) ? len : 11;
+ } // endelse
+
+ break;
+ default:
+ break;
+ } // endswitch type
+
+ if (fp->flags & UNSIGNED_FLAG)
+ pcf->Flags |= U_UNSIGNED;
+
+ if (fp->flags & ZEROFILL_FLAG)
+ pcf->Flags |= U_ZEROFILL;
+
+ // This is used to skip null bit
+ if (fp->real_maybe_null())
+ pcf->Flags |= U_NULLS;
+
+ // Mark virtual columns as such
+ if (fp->vcol_info && !fp->stored_in_db)
+ pcf->Flags |= U_VIRTUAL;
+
+ pcf->Key= 0; // Not used when called from MySQL
+
+ // Get the comment if any
+ 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;
+ } else
+ pcf->Remark= NULL;
+
+ return fldp;
+} // end of GetColumnOption
+
+/****************************************************************************/
+/* Returns the index description structure used to make the index. */
+/****************************************************************************/
+PIXDEF ha_connect::GetIndexInfo(TABLE_SHARE *s)
+{
+ char *name, *pn;
+ bool unique;
+ PIXDEF xdp, pxd=NULL, toidx= NULL;
+ PKPDEF kpp, pkp;
+ KEY kp;
+ PGLOBAL& g= xp->g;
+
+ if (!s)
+ s= table->s;
+
+ for (int n= 0; (unsigned)n < s->keynames.count; n++) {
+ if (xtrace)
+ htrc("Getting created index %d info\n", n + 1);
+
+ // Find the index to describe
+ kp= s->key_info[n];
+
+ // Now get index information
+ 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;
+ pkp= NULL;
+
+ // Allocate the index description block
+ xdp= new(g) INDEXDEF(name, unique, n);
+
+ // Get the the key parts info
+ for (int k= 0; (unsigned)k < kp.user_defined_key_parts; k++) {
+ pn= (char*)kp.key_part[k].field->field_name;
+ name= (char*)PlugSubAlloc(g, NULL, strlen(pn) + 1);
+ strcpy(name, pn); // This is probably unuseful
+
+ // Allocate the key part description block
+ kpp= new(g) KPARTDEF(name, k + 1);
+ kpp->SetKlen(kp.key_part[k].length);
+
+#if 0 // NIY
+ // Index on auto increment column can be an XXROW index
+ if (kp.key_part[k].field->flags & AUTO_INCREMENT_FLAG &&
+ kp.uder_defined_key_parts == 1) {
+ char *type= GetStringOption("Type", "DOS");
+ TABTYPE typ= GetTypeID(type);
+
+ xdp->SetAuto(IsTypeFixed(typ));
+ } // endif AUTO_INCREMENT
+#endif // 0
+
+ if (pkp)
+ pkp->SetNext(kpp);
+ else
+ xdp->SetToKeyParts(kpp);
+
+ pkp= kpp;
+ } // endfor k
+
+ xdp->SetNParts(kp.user_defined_key_parts);
+
+ if (pxd)
+ pxd->SetNext(xdp);
+ else
+ toidx= xdp;
+
+ pxd= xdp;
+ } // endfor n
+
+ return toidx;
+} // end of GetIndexInfo
+
+const char *ha_connect::GetDBName(const char* name)
+{
+ return (name) ? name : table->s->db.str;
+} // end of GetDBName
+
+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. */
+/****************************************************************************/
+int ha_connect::GetColNameLen(Field *fp)
+{
+ int n;
+ PFOS fop= GetFieldOptionStruct(fp);
+
+ // Now get the column name length
+ if (fop && fop->special)
+ n= strlen(fop->special) + 1;
+ else
+ n= strlen(fp->field_name);
+
+ return n;
+} // end of GetColNameLen
+
+/****************************************************************************/
+/* Returns the column real or special name of a field. */
+/****************************************************************************/
+char *ha_connect::GetColName(Field *fp)
+{
+ PFOS fop= GetFieldOptionStruct(fp);
+
+ return (fop && fop->special) ? fop->special : (char*)fp->field_name;
+} // end of GetColName
+
+/****************************************************************************/
+/* Adds the column real or special name of a field to a string. */
+/****************************************************************************/
+void ha_connect::AddColName(char *cp, Field *fp)
+{
+ PFOS fop= GetFieldOptionStruct(fp);
+
+ // Now add the column name
+ if (fop && fop->special)
+ // The prefix * mark the column as "special"
+ strcat(strcpy(cp, "*"), strupr(fop->special));
+ else
+ strcpy(cp, (char*)fp->field_name);
+
+} // end of AddColName
+#endif // 0
+
+/****************************************************************************/
+/* Get the table description block of a CONNECT table. */
+/****************************************************************************/
+PTDB ha_connect::GetTDB(PGLOBAL g)
+{
+ const char *table_name;
+ PTDB tp;
+
+ // Double test to be on the safe side
+ if (!g || !table)
+ return NULL;
+
+ table_name= GetTableName();
+
+ if (!xp->CheckQuery(valid_query_id) && tdbp
+ && !stricmp(tdbp->GetName(), table_name)
+ && (tdbp->GetMode() == xmod
+ || tdbp->GetAmType() == TYPE_AM_XML)) {
+ tp= tdbp;
+// tp->SetMode(xmod);
+ } else if ((tp= CntGetTDB(g, table_name, xmod, this))) {
+ valid_query_id= xp->last_query_id;
+ tp->SetMode(xmod);
+ } else
+ htrc("GetTDB: %s\n", g->Message);
+
+ return tp;
+} // end of GetTDB
+
+/****************************************************************************/
+/* Open a CONNECT table, restricting column list if cols is true. */
+/****************************************************************************/
+int ha_connect::OpenTable(PGLOBAL g, bool del)
+{
+ bool rc= false;
+ char *c1= NULL, *c2=NULL;
+
+ // Double test to be on the safe side
+ if (!g || !table) {
+ htrc("OpenTable logical error; g=%p table=%p\n", g, table);
+ return HA_ERR_INITIALIZATION;
+ } // endif g
+
+ if (!(tdbp= GetTDB(g)))
+ return RC_FX;
+ else if (tdbp->IsReadOnly())
+ switch (xmod) {
+ case MODE_WRITE:
+ case MODE_INSERT:
+ case MODE_UPDATE:
+ case MODE_DELETE:
+ strcpy(g->Message, MSG(READ_ONLY));
+ return HA_ERR_TABLE_READONLY;
+ default:
+ break;
+ } // endswitch xmode
+
+ if (xmod != MODE_INSERT || tdbp->GetAmType() == TYPE_AM_ODBC
+ || tdbp->GetAmType() == TYPE_AM_MYSQL) {
+ // Get the list of used fields (columns)
+ char *p;
+ unsigned int k1, k2, n1, n2;
+ Field* *field;
+ Field* fp;
+ MY_BITMAP *map= (xmod == MODE_INSERT) ? table->write_set : 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; 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, fp->field_index)) {
+ n2+= (strlen(fp->field_name) + 1);
+ k2++;
+ } // endif
+
+ } // endfor field
+
+ if (k1) {
+ p= c1= (char*)PlugSubAlloc(g, NULL, n1);
+
+ 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
+
+ *p= '\0'; // mark end of list
+ } // endif k1
+
+ if (k2) {
+ p= c2= (char*)PlugSubAlloc(g, NULL, n2);
+
+ 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
+
+ *p= '\0'; // mark end of list
+ } // endif k2
+
+ } // endif xmod
+
+ // Open the table
+ if (!(rc= CntOpenTable(g, tdbp, xmod, c1, c2, del, this))) {
+ istable= true;
+// strmake(tname, table_name, sizeof(tname)-1);
+
+ // We may be in a create index query
+ if (xmod == MODE_ANY && *tdbp->GetName() != '#') {
+ // The current indexes
+ PIXDEF oldpix= GetIndexInfo();
+ } // endif xmod
+
+ } else
+ htrc("OpenTable: %s\n", g->Message);
+
+ if (rc) {
+ tdbp= NULL;
+ valid_info= false;
+ } // endif rc
+
+ return (rc) ? HA_ERR_INITIALIZATION : 0;
+} // end of OpenTable
+
+
+/****************************************************************************/
+/* IsOpened: returns true if the table is already opened. */
+/****************************************************************************/
+bool ha_connect::IsOpened(void)
+{
+ return (!xp->CheckQuery(valid_query_id) && tdbp
+ && tdbp->GetUse() == USE_OPEN);
+} // end of IsOpened
+
+
+/****************************************************************************/
+/* Close a CONNECT table. */
+/****************************************************************************/
+int ha_connect::CloseTable(PGLOBAL g)
+{
+ int rc= CntCloseTable(g, tdbp);
+ tdbp= NULL;
+ sdvalin=NULL;
+ sdvalout=NULL;
+ valid_info= false;
+ indexing= -1;
+ return rc;
+} // end of CloseTable
+
+
+/***********************************************************************/
+/* Make a pseudo record from current row values. Specific to MySQL. */
+/***********************************************************************/
+int ha_connect::MakeRecord(char *buf)
+{
+ char *p, *fmt, val[32];
+ int rc= 0;
+ Field* *field;
+ Field *fp;
+ my_bitmap_map *org_bitmap;
+ CHARSET_INFO *charset= tdbp->data_charset();
+//MY_BITMAP readmap;
+ MY_BITMAP *map;
+ PVAL value;
+ PCOL colp= NULL;
+ DBUG_ENTER("ha_connect::MakeRecord");
+
+ if (xtrace > 1)
+ htrc("Maps: read=%08X write=%08X vcol=%08X defr=%08X defw=%08X\n",
+ *table->read_set->bitmap, *table->write_set->bitmap,
+ *table->vcol_set->bitmap,
+ *table->def_read_set.bitmap, *table->def_write_set.bitmap);
+
+ // Avoid asserts in field::store() for columns that are not updated
+ org_bitmap= dbug_tmp_use_all_columns(table, table->write_set);
+
+ // This is for variable_length rows
+ memset(buf, 0, table->s->null_bytes);
+
+ // When sorting read_set selects all columns, so we use def_read_set
+ map= (MY_BITMAP *)&table->def_read_set;
+
+ // Make the pseudo record from field values
+ for (field= table->field; *field && !rc; field++) {
+ fp= *field;
+
+ if (fp->vcol_info && !fp->stored_in_db)
+ continue; // This is a virtual column
+
+ 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 ((!mrr || colp->GetKcol()) &&
+ !stricmp(colp->GetName(), (char*)fp->field_name))
+ break;
+
+ if (!colp) {
+ if (mrr)
+ continue;
+
+ htrc("Column %s not found\n", fp->field_name);
+ dbug_tmp_restore_column_map(table->write_set, org_bitmap);
+ DBUG_RETURN(HA_ERR_WRONG_IN_RECORD);
+ } // endif colp
+
+ value= colp->GetValue();
+
+ // All this could be better optimized
+ if (!value->IsNull()) {
+ switch (value->GetType()) {
+ case TYPE_DATE:
+ if (!sdvalout)
+ sdvalout= AllocateValue(xp->g, TYPE_STRING, 20);
+
+ switch (fp->type()) {
+ case MYSQL_TYPE_DATE:
+ fmt= "%Y-%m-%d";
+ break;
+ case MYSQL_TYPE_TIME:
+ fmt= "%H:%M:%S";
+ break;
+ case MYSQL_TYPE_YEAR:
+ fmt= "%Y";
+ break;
+ default:
+ fmt= "%Y-%m-%d %H:%M:%S";
+ break;
+ } // endswitch type
+
+ // Get date in the format required by MySQL fields
+ value->FormatValue(sdvalout, fmt);
+ p= sdvalout->GetCharValue();
+ break;
+ case TYPE_DOUBLE:
+ p= NULL;
+ break;
+ case TYPE_STRING:
+ // Passthru
+ default:
+ p= value->GetCharString(val);
+ break;
+ } // endswitch Type
+
+ if (p) {
+ if (fp->store(p, strlen(p), charset, CHECK_FIELD_WARN)) {
+ // Avoid "error" on null fields
+ if (value->GetIntValue())
+ rc= HA_ERR_WRONG_IN_RECORD;
+
+ DBUG_PRINT("MakeRecord", ("%s", p));
+ } // endif store
+
+ } else
+ if (fp->store(value->GetFloatValue())) {
+// rc= HA_ERR_WRONG_IN_RECORD; a Warning was ignored
+ char buf[128];
+ THD *thd= ha_thd();
+
+ sprintf(buf, "Out of range value for column '%s' at row %ld",
+ fp->field_name,
+ thd->get_stmt_da()->current_row_for_warning());
+
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, buf);
+ DBUG_PRINT("MakeRecord", ("%s", value->GetCharString(val)));
+ } // endif store
+
+ fp->set_notnull();
+ } else
+ fp->set_null();
+
+ } // endif bitmap
+
+ } // endfor field
+
+ // This is copied from ha_tina and is necessary to avoid asserts
+ dbug_tmp_restore_column_map(table->write_set, org_bitmap);
+ DBUG_RETURN(rc);
+} // end of MakeRecord
+
+
+/***********************************************************************/
+/* Set row values from a MySQL pseudo record. Specific to MySQL. */
+/***********************************************************************/
+int ha_connect::ScanRecord(PGLOBAL g, uchar *buf)
+{
+ char attr_buffer[1024];
+ char data_buffer[1024];
+ char *fmt;
+ int rc= 0;
+ PCOL colp;
+ PVAL value;
+ Field *fp;
+ PTDBASE tp= (PTDBASE)tdbp;
+ String attribute(attr_buffer, sizeof(attr_buffer),
+ table->s->table_charset);
+ my_bitmap_map *bmap= dbug_tmp_use_all_columns(table, table->read_set);
+ const CHARSET_INFO *charset= tdbp->data_charset();
+ String data_charset_value(data_buffer, sizeof(data_buffer), charset);
+
+ // Scan the pseudo record for field values and set column values
+ for (Field **field=table->field ; *field ; field++) {
+ fp= *field;
+
+ if ((fp->vcol_info && !fp->stored_in_db) ||
+ fp->option_struct->special)
+ continue; // Is a virtual column possible here ???
+
+ if ((xmod == MODE_INSERT && tdbp->GetAmType() != TYPE_AM_MYSQL
+ && tdbp->GetAmType() != TYPE_AM_ODBC) ||
+ bitmap_is_set(table->write_set, fp->field_index)) {
+ for (colp= tp->GetSetCols(); colp; colp= colp->GetNext())
+ if (!stricmp(colp->GetName(), fp->field_name))
+ break;
+
+ if (!colp) {
+ htrc("Column %s not found\n", fp->field_name);
+ rc= HA_ERR_WRONG_IN_RECORD;
+ goto err;
+ } else
+ value= colp->GetValue();
+
+ // This is a used field, fill the value from the row buffer
+ // All this could be better optimized
+ if (fp->is_null()) {
+ if (colp->IsNullable())
+ value->SetNull(true);
+
+ value->Reset();
+ } else switch (value->GetType()) {
+ case TYPE_DOUBLE:
+ value->SetValue(fp->val_real());
+ break;
+ case TYPE_DATE:
+ if (!sdvalin)
+ sdvalin= (DTVAL*)AllocateValue(xp->g, TYPE_DATE, 19);
+
+ // Get date in the format produced by MySQL fields
+ switch (fp->type()) {
+ case MYSQL_TYPE_DATE:
+ fmt= "YYYY-MM-DD";
+ break;
+ case MYSQL_TYPE_TIME:
+ fmt= "hh:mm:ss";
+ break;
+ case MYSQL_TYPE_YEAR:
+ fmt= "YYYY";
+ break;
+ default:
+ fmt= "YYYY-MM-DD hh:mm:ss";
+ } // endswitch type
+
+ ((DTVAL*)sdvalin)->SetFormat(g, fmt, strlen(fmt));
+ fp->val_str(&attribute);
+ sdvalin->SetValue_psz(attribute.c_ptr_safe());
+ value->SetValue_pval(sdvalin);
+ break;
+ default:
+ fp->val_str(&attribute);
+
+ 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
+
+#ifdef NEWCHANGE
+ } else if (xmod == MODE_UPDATE) {
+ PCOL cp;
+
+ for (cp= tp->GetColumns(); cp; cp= cp->GetNext())
+ if (!stricmp(colp->GetName(), cp->GetName()))
+ break;
+
+ if (!cp) {
+ rc= HA_ERR_WRONG_IN_RECORD;
+ goto err;
+ } // endif cp
+
+ value->SetValue_pval(cp->GetValue());
+ } else // mode Insert
+ value->Reset();
+#else
+ } // endif bitmap_is_set
+#endif
+
+ } // endfor field
+
+ err:
+ dbug_tmp_restore_column_map(table->read_set, bmap);
+ return rc;
+} // end of ScanRecord
+
+
+/***********************************************************************/
+/* Check change in index column. Specific to MySQL. */
+/* Should be elaborated to check for real changes. */
+/***********************************************************************/
+int ha_connect::CheckRecord(PGLOBAL g, const uchar *oldbuf, uchar *newbuf)
+{
+ return ScanRecord(g, newbuf);
+} // end of dummy CheckRecord
+
+
+/***********************************************************************/
+/* Return the string representing an operator. */
+/***********************************************************************/
+const char *ha_connect::GetValStr(OPVAL vop, bool neg)
+{
+ const char *val;
+
+ switch (vop) {
+ case OP_EQ:
+ val= " = ";
+ break;
+ case OP_NE:
+ val= " <> ";
+ break;
+ case OP_GT:
+ val= " > ";
+ break;
+ case OP_GE:
+ val= " >= ";
+ break;
+ case OP_LT:
+ val= " < ";
+ break;
+ case OP_LE:
+ val= " <= ";
+ break;
+ case OP_IN:
+ val= (neg) ? " NOT IN (" : " IN (";
+ break;
+ case OP_NULL:
+ val= (neg) ? " IS NOT NULL" : " IS NULL";
+ break;
+ case OP_LIKE:
+ val= " LIKE ";
+ break;
+ case OP_XX:
+ val= (neg) ? " NOT BETWEEN " : " BETWEEN ";
+ break;
+ case OP_EXIST:
+ val= (neg) ? " NOT EXISTS " : " EXISTS ";
+ break;
+ case OP_AND:
+ val= " AND ";
+ break;
+ case OP_OR:
+ val= " OR ";
+ break;
+ case OP_NOT:
+ val= " NOT ";
+ break;
+ case OP_CNC:
+ val= " || ";
+ break;
+ case OP_ADD:
+ val= " + ";
+ break;
+ case OP_SUB:
+ val= " - ";
+ break;
+ case OP_MULT:
+ val= " * ";
+ break;
+ case OP_DIV:
+ val= " / ";
+ break;
+ default:
+ val= " ? ";
+ break;
+ } /* endswitch */
+
+ return val;
+} // end of GetValStr
+
+
+/***********************************************************************/
+/* Check the WHERE condition and return a CONNECT filter. */
+/***********************************************************************/
+PFIL ha_connect::CondFilter(PGLOBAL g, Item *cond)
+{
+ unsigned int i;
+ bool ismul= false;
+ OPVAL vop= OP_XX;
+ PFIL filp= NULL;
+
+ if (!cond)
+ return NULL;
+
+ if (xtrace)
+ htrc("Cond type=%d\n", cond->type());
+
+ if (cond->type() == COND::COND_ITEM) {
+ PFIL fp;
+ Item_cond *cond_item= (Item_cond *)cond;
+
+ if (xtrace)
+ htrc("Cond: Ftype=%d name=%s\n", cond_item->functype(),
+ cond_item->func_name());
+
+ switch (cond_item->functype()) {
+ case Item_func::COND_AND_FUNC: vop= OP_AND; break;
+ case Item_func::COND_OR_FUNC: vop= OP_OR; break;
+ default: return NULL;
+ } // endswitch functype
+
+ List<Item>* arglist= cond_item->argument_list();
+ List_iterator<Item> li(*arglist);
+ Item *subitem;
+
+ for (i= 0; i < arglist->elements; i++)
+ if ((subitem= li++)) {
+ if (!(fp= CondFilter(g, subitem))) {
+ if (vop == OP_OR)
+ return NULL;
+ } else
+ filp= (filp) ? MakeFilter(g, filp, vop, fp) : fp;
+
+ } else
+ return NULL;
+
+ } else if (cond->type() == COND::FUNC_ITEM) {
+ unsigned int i;
+ bool iscol, neg= FALSE;
+ PCOL colp[2]= {NULL,NULL};
+ PPARM pfirst= NULL, pprec= NULL;
+ POPER pop;
+ Item_func *condf= (Item_func *)cond;
+ Item* *args= condf->arguments();
+
+ if (xtrace)
+ htrc("Func type=%d argnum=%d\n", condf->functype(),
+ condf->argument_count());
+
+ switch (condf->functype()) {
+ case Item_func::EQUAL_FUNC:
+ case Item_func::EQ_FUNC: vop= OP_EQ; break;
+ case Item_func::NE_FUNC: vop= OP_NE; break;
+ case Item_func::LT_FUNC: vop= OP_LT; break;
+ case Item_func::LE_FUNC: vop= OP_LE; break;
+ case Item_func::GE_FUNC: vop= OP_GE; break;
+ case Item_func::GT_FUNC: vop= OP_GT; break;
+ case Item_func::IN_FUNC: vop= OP_IN;
+ case Item_func::BETWEEN:
+ ismul= true;
+ neg= ((Item_func_opt_neg *)condf)->negated;
+ break;
+ default: return NULL;
+ } // endswitch functype
+
+ pop= (POPER)PlugSubAlloc(g, NULL, sizeof(OPER));
+ pop->Name= NULL;
+ pop->Val=vop;
+ pop->Mod= 0;
+
+ if (condf->argument_count() < 2)
+ return NULL;
+
+ for (i= 0; i < condf->argument_count(); i++) {
+ if (xtrace)
+ htrc("Argtype(%d)=%d\n", i, args[i]->type());
+
+ if (i >= 2 && !ismul) {
+ if (xtrace)
+ htrc("Unexpected arg for vop=%d\n", vop);
+
+ continue;
+ } // endif i
+
+ if ((iscol= args[i]->type() == COND::FIELD_ITEM)) {
+ Item_field *pField= (Item_field *)args[i];
+
+ // IN and BETWEEN clauses should be col VOP list
+ if (i && ismul)
+ return NULL;
+
+ if (pField->field->table != table ||
+ !(colp[i]= tdbp->ColDB(g, (PSZ)pField->field->field_name, 0)))
+ return NULL; // Column does not belong to this table
+
+ if (xtrace) {
+ htrc("Field index=%d\n", pField->field->field_index);
+ htrc("Field name=%s\n", pField->field->field_name);
+ } // endif xtrace
+
+ } else {
+ char buff[256];
+ String *res, tmp(buff, sizeof(buff), &my_charset_bin);
+ Item_basic_constant *pval= (Item_basic_constant *)args[i];
+ PPARM pp= (PPARM)PlugSubAlloc(g, NULL, sizeof(PARM));
+
+ // IN and BETWEEN clauses should be col VOP list
+ if (!i && (ismul))
+ return NULL;
+
+ if ((res= pval->val_str(&tmp)) == NULL)
+ return NULL; // To be clarified
+
+ switch (args[i]->real_type()) {
+ case COND::STRING_ITEM:
+ pp->Type= TYPE_STRING;
+ pp->Value= PlugSubAlloc(g, NULL, res->length() + 1);
+ strncpy((char*)pp->Value, res->ptr(), res->length() + 1);
+ break;
+ case COND::INT_ITEM:
+ pp->Type= TYPE_INT;
+ pp->Value= PlugSubAlloc(g, NULL, sizeof(int));
+ *((int*)pp->Value)= (int)pval->val_int();
+ break;
+ case COND::DATE_ITEM:
+ pp->Type= TYPE_DATE;
+ pp->Value= PlugSubAlloc(g, NULL, sizeof(int));
+ *((int*)pp->Value)= (int)pval->val_int_from_date();
+ break;
+ case COND::REAL_ITEM:
+ pp->Type= TYPE_DOUBLE;
+ pp->Value= PlugSubAlloc(g, NULL, sizeof(double));
+ *((double*)pp->Value)= pval->val_real();
+ break;
+ case COND::DECIMAL_ITEM:
+ pp->Type= TYPE_DOUBLE;
+ pp->Value= PlugSubAlloc(g, NULL, sizeof(double));
+ *((double*)pp->Value)= pval->val_real_from_decimal();
+ break;
+ case COND::CACHE_ITEM: // Possible ???
+ case COND::NULL_ITEM: // TODO: handle this
+ default:
+ return NULL;
+ } // endswitch type
+
+ if (xtrace)
+ htrc("Value=%.*s\n", res->length(), res->ptr());
+
+ // Append the value to the argument list
+ if (pprec)
+ pprec->Next= pp;
+ else
+ pfirst= pp;
+
+ pp->Domain= i;
+ pp->Next= NULL;
+ pprec= pp;
+ } // endif type
+
+ } // endfor i
+
+ filp= MakeFilter(g, colp, pop, pfirst, neg);
+ } else {
+ if (xtrace)
+ htrc("Unsupported condition\n");
+
+ return NULL;
+ } // endif's type
+
+ return filp;
+} // end of CondFilter
+
+/***********************************************************************/
+/* Check the WHERE condition and return a MYSQL/ODBC/WQL filter. */
+/***********************************************************************/
+PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, AMT tty, Item *cond)
+{
+ char *body= filp->Body;
+ unsigned int i;
+ bool ismul= false, x= (tty == TYPE_AM_MYX || tty == TYPE_AM_XDBC);
+ OPVAL vop= OP_XX;
+
+ if (!cond)
+ return NULL;
+
+ if (xtrace)
+ htrc("Cond type=%d\n", cond->type());
+
+ if (cond->type() == COND::COND_ITEM) {
+ char *p1, *p2;
+ Item_cond *cond_item= (Item_cond *)cond;
+
+ if (x)
+ return NULL;
+
+ if (xtrace)
+ htrc("Cond: Ftype=%d name=%s\n", cond_item->functype(),
+ cond_item->func_name());
+
+ switch (cond_item->functype()) {
+ case Item_func::COND_AND_FUNC: vop= OP_AND; break;
+ case Item_func::COND_OR_FUNC: vop= OP_OR; break;
+ default: return NULL;
+ } // endswitch functype
+
+ List<Item>* arglist= cond_item->argument_list();
+ List_iterator<Item> li(*arglist);
+ Item *subitem;
+
+ p1= body + strlen(body);
+ strcpy(p1, "(");
+ p2= p1 + 1;
+
+ for (i= 0; i < arglist->elements; i++)
+ if ((subitem= li++)) {
+ if (!CheckCond(g, filp, tty, subitem)) {
+ if (vop == OP_OR)
+ return NULL;
+ else
+ *p2= 0;
+
+ } else {
+ p1= p2 + strlen(p2);
+ strcpy(p1, GetValStr(vop, FALSE));
+ p2= p1 + strlen(p1);
+ } // endif CheckCond
+
+ } else
+ return NULL;
+
+ if (*p1 != '(')
+ strcpy(p1, ")");
+ else
+ return NULL;
+
+ } else if (cond->type() == COND::FUNC_ITEM) {
+ unsigned int i;
+// int n;
+ bool iscol, neg= FALSE;
+ Item_func *condf= (Item_func *)cond;
+ Item* *args= condf->arguments();
+
+ if (xtrace)
+ htrc("Func type=%d argnum=%d\n", condf->functype(),
+ condf->argument_count());
+
+// neg= condf->
+
+ switch (condf->functype()) {
+ case Item_func::EQUAL_FUNC:
+ case Item_func::EQ_FUNC: vop= OP_EQ; break;
+ case Item_func::NE_FUNC: vop= OP_NE; break;
+ case Item_func::LT_FUNC: vop= OP_LT; break;
+ case Item_func::LE_FUNC: vop= OP_LE; break;
+ case Item_func::GE_FUNC: vop= OP_GE; break;
+ case Item_func::GT_FUNC: vop= OP_GT; break;
+ case Item_func::IN_FUNC: vop= OP_IN;
+ case Item_func::BETWEEN:
+ ismul= true;
+ neg= ((Item_func_opt_neg *)condf)->negated;
+ break;
+ default: return NULL;
+ } // endswitch functype
+
+ if (condf->argument_count() < 2)
+ return NULL;
+ else if (ismul && tty == TYPE_AM_WMI)
+ return NULL; // Not supported by WQL
+
+ if (x && (neg || !(vop == OP_EQ || vop == OP_IN)))
+ return NULL;
+
+ for (i= 0; i < condf->argument_count(); i++) {
+ if (xtrace)
+ htrc("Argtype(%d)=%d\n", i, args[i]->type());
+
+ if (i >= 2 && !ismul) {
+ if (xtrace)
+ htrc("Unexpected arg for vop=%d\n", vop);
+
+ continue;
+ } // endif i
+
+ if ((iscol= args[i]->type() == COND::FIELD_ITEM)) {
+ const char *fnm;
+ ha_field_option_struct *fop;
+ Item_field *pField= (Item_field *)args[i];
+
+ if (x && i)
+ return NULL;
+
+ if (pField->field->table != table)
+ return NULL; // Field does not belong to this table
+ else
+ fop= GetFieldOptionStruct(pField->field);
+
+ 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;
+
+ } else if (tty == TYPE_AM_TBL)
+ return NULL;
+ else
+ fnm= pField->field->field_name;
+
+ if (xtrace) {
+ htrc("Field index=%d\n", pField->field->field_index);
+ htrc("Field name=%s\n", pField->field->field_name);
+ } // endif xtrace
+
+ // IN and BETWEEN clauses should be col VOP list
+ if (i && ismul)
+ 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]->real_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)
+ htrc("Value=%.*s\n", res->length(), res->ptr());
+
+ // IN and BETWEEN clauses should be col VOP list
+ if (!i && (x || ismul))
+ return NULL;
+
+ if (!x) {
+ // Append the value to the filter
+ if (args[i]->field_type() == MYSQL_TYPE_VARCHAR)
+ strcat(strcat(strcat(body, "'"), res->ptr()), "'");
+ else
+ strncat(body, res->ptr(), res->length());
+
+ } else {
+ if (args[i]->field_type() == MYSQL_TYPE_VARCHAR) {
+ // Add the command to the list
+ PCMD *ncp, cmdp= new(g) CMD(g, (char*)res->ptr());
+
+ for (ncp= &filp->Cmds; *ncp; ncp= &(*ncp)->Next) ;
+
+ *ncp= cmdp;
+ } else
+ return NULL;
+
+ } // endif x
+
+ } // endif
+
+ if (!x) {
+ if (!i)
+ strcat(body, GetValStr(vop, neg));
+ else if (vop == OP_XX && i == 1)
+ strcat(body, " AND ");
+ else if (vop == OP_IN)
+ strcat(body, (i == condf->argument_count() - 1) ? ")" : ",");
+
+ } // endif x
+
+ } // endfor i
+
+ if (x)
+ filp->Op= vop;
+
+ } else {
+ if (xtrace)
+ htrc("Unsupported condition\n");
+
+ return NULL;
+ } // endif's type
+
+ return filp;
+} // end of CheckCond
+
+
+ /**
+ Push condition down to the table handler.
+
+ @param cond Condition to be pushed. The condition tree must not be
+ modified by the caller.
+
+ @return
+ The 'remainder' condition that caller must use to filter out records.
+ NULL means the handler will not return rows that do not match the
+ passed condition.
+
+ @note
+ CONNECT handles the filtering only for table types that construct
+ an SQL or WQL query, but still leaves it to MySQL because only some
+ parts of the filter may be relevant.
+ The first suballocate finds the position where the string will be
+ constructed in the sarea. The second one does make the suballocation
+ with the proper length.
+ */
+const COND *ha_connect::cond_push(const COND *cond)
+{
+ DBUG_ENTER("ha_connect::cond_push");
+
+ if (tdbp) {
+ PGLOBAL& g= xp->g;
+ AMT tty= tdbp->GetAmType();
+ bool x= (tty == TYPE_AM_MYX || tty == TYPE_AM_XDBC);
+ bool b= (tty == TYPE_AM_WMI || tty == TYPE_AM_ODBC ||
+ tty == TYPE_AM_TBL || tty == TYPE_AM_MYSQL ||
+ tty == TYPE_AM_PLG || x);
+
+ if (b) {
+ PCFIL filp= (PCFIL)PlugSubAlloc(g, NULL, sizeof(CONDFIL));
+
+ filp->Body= (char*)PlugSubAlloc(g, NULL, (x) ? 128 : 0);
+ *filp->Body= 0;
+ filp->Op= OP_XX;
+ filp->Cmds= NULL;
+
+ if (CheckCond(g, filp, tty, (Item *)cond)) {
+ if (xtrace)
+ htrc("cond_push: %s\n", filp->Body);
+
+ if (!x)
+ PlugSubAlloc(g, NULL, strlen(filp->Body) + 1);
+ else
+ cond= NULL; // Does this work?
+
+ tdbp->SetCondFil(filp);
+ } else if (x && cond)
+ tdbp->SetCondFil(filp); // Wrong filter
+
+ } else
+ tdbp->SetFilter(CondFilter(g, (Item *)cond));
+
+ } // endif tdbp
+
+ // Let MySQL do the filtering
+ DBUG_RETURN(cond);
+} // end of cond_push
+
+/**
+ Number of rows in table. It will only be called if
+ (table_flags() & (HA_HAS_RECORDS | HA_STATS_RECORDS_IS_EXACT)) != 0
+*/
+ha_rows ha_connect::records()
+{
+ if (!valid_info)
+ info(HA_STATUS_VARIABLE);
+
+ if (tdbp && tdbp->Cardinality(NULL))
+ return stats.records;
+ else
+ return HA_POS_ERROR;
+
+} // end of records
+
+
+/**
+ Return an error message specific to this handler.
+
+ @param error error code previously returned by handler
+ @param buf pointer to String where to add error message
+
+ @return
+ Returns true if this is a temporary error
+*/
+bool ha_connect::get_error_message(int error, String* buf)
+{
+ DBUG_ENTER("ha_connect::get_error_message");
+
+ if (xp && xp->g) {
+ PGLOBAL g= xp->g;
+ char msg[3072]; // MAX_STR * 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);
+
+ if (trace)
+ htrc("GEM(%u): %s\n", len, g->Message);
+
+ 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
+
+
+/**
+ @brief
+ Used for opening tables. The name will be the name of the file.
+
+ @details
+ A table is opened when it needs to be opened; e.g. when a request comes in
+ for a SELECT on the table (tables are not open and closed for each request,
+ they are cached).
+
+ Called from handler.cc by handler::ha_open(). The server opens all tables by
+ calling ha_open() which then calls the handler specific open().
+
+ @note
+ For CONNECT no open can be done here because field information is not yet
+ updated. >>>>> TO BE CHECKED <<<<<
+ (Thread information could be get by using 'ha_thd')
+
+ @see
+ handler::ha_open() in handler.cc
+*/
+int ha_connect::open(const char *name, int mode, uint test_if_locked)
+{
+ int rc= 0;
+ DBUG_ENTER("ha_connect::open");
+
+ if (xtrace)
+ htrc("open: name=%s mode=%d test=%u\n", name, mode, test_if_locked);
+
+ if (!(share= get_share()))
+ DBUG_RETURN(1);
+
+ thr_lock_data_init(&share->lock,&lock,NULL);
+
+ // Try to get the user if possible
+ xp= GetUser(ha_thd(), xp);
+ PGLOBAL g= (xp) ? xp->g : NULL;
+
+ // Try to set the database environment
+ if (g) {
+ rc= (CntCheckDB(g, this, name)) ? (-2) : 0;
+
+ if (g->Mrr) {
+ // This should only happen for the mrr secondary handler
+ mrr= true;
+ g->Mrr= false;
+ } else
+ mrr= false;
+
+ } else
+ rc= HA_ERR_INTERNAL_ERROR;
+
+ DBUG_RETURN(rc);
+} // end of open
+
+/**
+ @brief
+ Make the indexes for this table
+*/
+int ha_connect::optimize(THD* thd, HA_CHECK_OPT* check_opt)
+{
+ int rc= 0;
+ PGLOBAL& g= xp->g;
+ PDBUSER dup= PlgGetUser(g);
+
+ // Ignore error on the opt file
+ dup->Check &= ~CHK_OPT;
+ tdbp= GetTDB(g);
+ dup->Check |= CHK_OPT;
+
+ if (tdbp) {
+ bool b= ((PTDBASE)tdbp)->GetDef()->Indexable();
+
+ if ((rc= ((PTDBASE)tdbp)->ResetTableOpt(g, true, b))) {
+ if (rc == RC_INFO) {
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
+ rc= 0;
+ } else
+ rc= HA_ERR_INTERNAL_ERROR;
+
+ } // endif rc
+
+ } else
+ rc= HA_ERR_INTERNAL_ERROR;
+
+ return rc;
+} // end of optimize
+
+/**
+ @brief
+ Closes a table.
+
+ @details
+ Called from sql_base.cc, sql_select.cc, and table.cc. In sql_select.cc it is
+ only used to close up temporary tables or during the process where a
+ temporary table is converted over to being a myisam table.
+
+ For sql_base.cc look at close_data_tables().
+
+ @see
+ sql_base.cc, sql_select.cc and table.cc
+*/
+int ha_connect::close(void)
+{
+ int rc= 0;
+ DBUG_ENTER("ha_connect::close");
+
+ // If this is called by a later query, the table may have
+ // been already closed and the tdbp is not valid anymore.
+ if (tdbp && xp->last_query_id == valid_query_id)
+ rc= CloseTable(xp->g);
+
+ DBUG_RETURN(rc);
+} // end of close
+
+
+/**
+ @brief
+ write_row() inserts a row. No extra() hint is given currently if a bulk load
+ is happening. buf() is a byte array of data. You can use the field
+ information to extract the data from the native byte array type.
+
+ @details
+ Example of this would be:
+ @code
+ for (Field **field=table->field ; *field ; field++)
+ {
+ ...
+ }
+ @endcode
+
+ See ha_tina.cc for an example of extracting all of the data as strings.
+ ha_berekly.cc has an example of how to store it intact by "packing" it
+ for ha_berkeley's own native storage type.
+
+ See the note for update_row() on auto_increments and timestamps. This
+ case also applies to write_row().
+
+ Called from item_sum.cc, item_sum.cc, sql_acl.cc, sql_insert.cc,
+ sql_insert.cc, sql_select.cc, sql_table.cc, sql_udf.cc, and sql_update.cc.
+
+ @see
+ item_sum.cc, item_sum.cc, sql_acl.cc, sql_insert.cc,
+ sql_insert.cc, sql_select.cc, sql_table.cc, sql_udf.cc and sql_update.cc
+*/
+int ha_connect::write_row(uchar *buf)
+{
+ int rc= 0;
+ 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())
+ CloseTable(g);
+
+ if ((rc= OpenTable(g)))
+ DBUG_RETURN(rc);
+
+ } // endif isopened
+
+ if (tdbp->GetMode() == MODE_ANY)
+ DBUG_RETURN(0);
+
+#if 0 // AUTO_INCREMENT NIY
+ if (table->next_number_field && buf == table->record[0]) {
+ int error;
+
+ if ((error= update_auto_increment()))
+ return error;
+
+ } // endif nex_number_field
+#endif // 0
+
+ // Set column values from the passed pseudo record
+ if ((rc= ScanRecord(g, buf)))
+ DBUG_RETURN(rc);
+
+ // Return result code from write operation
+ if (CntWriteRow(g, tdbp)) {
+ DBUG_PRINT("write_row", ("%s", g->Message));
+ htrc("write_row: %s\n", g->Message);
+ rc= HA_ERR_INTERNAL_ERROR;
+ } // endif RC
+
+ DBUG_RETURN(rc);
+} // end of write_row
+
+
+/**
+ @brief
+ Yes, update_row() does what you expect, it updates a row. old_data will have
+ the previous row record in it, while new_data will have the newest data in it.
+ Keep in mind that the server can do updates based on ordering if an ORDER BY
+ clause was used. Consecutive ordering is not guaranteed.
+
+ @details
+ Currently new_data will not have an updated auto_increament record, or
+ and updated timestamp field. You can do these for example by doing:
+ @code
+ if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
+ table->timestamp_field->set_time();
+ if (table->next_number_field && record == table->record[0])
+ update_auto_increment();
+ @endcode
+
+ Called from sql_select.cc, sql_acl.cc, sql_update.cc, and sql_insert.cc.
+
+ @see
+ sql_select.cc, sql_acl.cc, sql_update.cc and sql_insert.cc
+*/
+int ha_connect::update_row(const uchar *old_data, uchar *new_data)
+{
+ int rc= 0;
+ PGLOBAL& g= xp->g;
+ DBUG_ENTER("ha_connect::update_row");
+
+ if (xtrace > 1)
+ htrc("update_row: old=%s new=%s\n", old_data, new_data);
+
+ // Check values for possible change in indexed column
+ if ((rc= CheckRecord(g, old_data, new_data)))
+ return rc;
+
+ if (CntUpdateRow(g, tdbp)) {
+ DBUG_PRINT("update_row", ("%s", g->Message));
+ htrc("update_row CONNECT: %s\n", g->Message);
+ rc= HA_ERR_INTERNAL_ERROR;
+ } // endif RC
+
+ DBUG_RETURN(rc);
+} // end of update_row
+
+
+/**
+ @brief
+ This will delete a row. buf will contain a copy of the row to be deleted.
+ The server will call this right after the current row has been called (from
+ either a previous rnd_nexT() or index call).
+
+ @details
+ If you keep a pointer to the last row or can access a primary key it will
+ make doing the deletion quite a bit easier. Keep in mind that the server does
+ not guarantee consecutive deletions. ORDER BY clauses can be used.
+
+ Called in sql_acl.cc and sql_udf.cc to manage internal table
+ information. Called in sql_delete.cc, sql_insert.cc, and
+ sql_select.cc. In sql_select it is used for removing duplicates
+ while in insert it is used for REPLACE calls.
+
+ @see
+ sql_acl.cc, sql_udf.cc, sql_delete.cc, sql_insert.cc and sql_select.cc
+*/
+int ha_connect::delete_row(const uchar *buf)
+{
+ int rc= 0;
+ DBUG_ENTER("ha_connect::delete_row");
+
+ if (CntDeleteRow(xp->g, tdbp, false)) {
+ rc= HA_ERR_INTERNAL_ERROR;
+ htrc("delete_row CONNECT: %s\n", xp->g->Message);
+ } // endif DeleteRow
+
+ DBUG_RETURN(rc);
+} // end of delete_row
+
+
+/****************************************************************************/
+/* We seem to come here at the begining of an index use. */
+/****************************************************************************/
+int ha_connect::index_init(uint idx, bool sorted)
+{
+ int rc;
+ PGLOBAL& g= xp->g;
+ DBUG_ENTER("index_init");
+
+ if (xtrace)
+ htrc("index_init: this=%p idx=%u sorted=%d\n", this, idx, 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) {
+ DBUG_PRINT("index_init", ("%s", g->Message));
+ htrc("index_init CONNECT: %s\n", g->Message);
+ active_index= MAX_KEY;
+ rc= HA_ERR_INTERNAL_ERROR;
+ } else {
+ if (((PTDBDOX)tdbp)->To_Kindex->GetNum_K()) {
+ if (((PTDBASE)tdbp)->GetFtype() != RECFM_NAF)
+ ((PTDBDOX)tdbp)->GetTxfp()->ResetBuffer(g);
+
+ active_index= idx;
+ } else // Void table
+ indexing= 0;
+
+ rc= 0;
+ } // endif indexing
+
+ if (xtrace)
+ htrc("index_init: rc=%d indexing=%d active_index=%d\n",
+ rc, indexing, active_index);
+
+ DBUG_RETURN(rc);
+} // end of index_init
+
+/****************************************************************************/
+/* We seem to come here at the end of an index use. */
+/****************************************************************************/
+int ha_connect::index_end()
+{
+ DBUG_ENTER("index_end");
+ active_index= MAX_KEY;
+ ds_mrr.dsmrr_close();
+ DBUG_RETURN(rnd_end());
+} // end of index_end
+
+
+/****************************************************************************/
+/* This is internally called by all indexed reading functions. */
+/****************************************************************************/
+int ha_connect::ReadIndexed(uchar *buf, OPVAL op, const uchar *key, uint key_len)
+{
+ int rc;
+
+//statistic_increment(ha_read_key_count, &LOCK_status);
+
+ switch (CntIndexRead(xp->g, tdbp, op, key, (int)key_len, mrr)) {
+ case RC_OK:
+ xp->fnd++;
+ rc= MakeRecord((char*)buf);
+ break;
+ case RC_EF: // End of file
+ rc= HA_ERR_END_OF_FILE;
+ break;
+ case RC_NF: // Not found
+ xp->nfd++;
+ rc= (op == OP_SAME) ? HA_ERR_END_OF_FILE : HA_ERR_KEY_NOT_FOUND;
+ break;
+ default: // Read error
+ DBUG_PRINT("ReadIndexed", ("%s", xp->g->Message));
+ htrc("ReadIndexed: %s\n", xp->g->Message);
+ rc= HA_ERR_INTERNAL_ERROR;
+ break;
+ } // endswitch RC
+
+ if (xtrace > 1)
+ htrc("ReadIndexed: op=%d rc=%d\n", op, rc);
+
+ table->status= (rc == RC_OK) ? 0 : STATUS_NOT_FOUND;
+ return rc;
+} // end of ReadIndexed
+
+
+#ifdef NOT_USED
+/**
+ @brief
+ Positions an index cursor to the index specified in the handle. Fetches the
+ row if available. If the key value is null, begin at the first key of the
+ index.
+*/
+int ha_connect::index_read_map(uchar *buf, const uchar *key,
+ key_part_map keypart_map __attribute__((unused)),
+ enum ha_rkey_function find_flag
+ __attribute__((unused)))
+{
+ DBUG_ENTER("ha_connect::index_read");
+ DBUG_RETURN(HA_ERR_WRONG_COMMAND);
+}
+#endif // NOT_USED
+
+
+/****************************************************************************/
+/* This is called by handler::index_read_map. */
+/****************************************************************************/
+int ha_connect::index_read(uchar * buf, const uchar * key, uint key_len,
+ enum ha_rkey_function find_flag)
+{
+ int rc;
+ OPVAL op= OP_XX;
+ DBUG_ENTER("ha_connect::index_read");
+
+ switch(find_flag) {
+ case HA_READ_KEY_EXACT: op= OP_EQ; break;
+ case HA_READ_AFTER_KEY: op= OP_GT; break;
+ case HA_READ_KEY_OR_NEXT: op= OP_GE; break;
+ default: DBUG_RETURN(-1); break;
+ } // endswitch find_flag
+
+ if (xtrace > 1)
+ htrc("%p index_read: op=%d\n", this, op);
+
+ if (indexing > 0)
+ rc= ReadIndexed(buf, op, key, key_len);
+ else
+ rc= HA_ERR_INTERNAL_ERROR;
+
+ DBUG_RETURN(rc);
+} // end of index_read
+
+
+/**
+ @brief
+ Used to read forward through the index.
+*/
+int ha_connect::index_next(uchar *buf)
+{
+ int rc;
+ DBUG_ENTER("ha_connect::index_next");
+ //statistic_increment(ha_read_next_count, &LOCK_status);
+
+ if (indexing > 0)
+ rc= ReadIndexed(buf, OP_NEXT);
+ else if (!indexing)
+ rc= rnd_next(buf);
+ else
+ rc= HA_ERR_INTERNAL_ERROR;
+
+ DBUG_RETURN(rc);
+} // end of index_next
+
+
+#ifdef NOT_USED
+/**
+ @brief
+ Used to read backwards through the index.
+*/
+int ha_connect::index_prev(uchar *buf)
+{
+ DBUG_ENTER("ha_connect::index_prev");
+ DBUG_RETURN(HA_ERR_WRONG_COMMAND);
+}
+#endif // NOT_USED
+
+
+/**
+ @brief
+ index_first() asks for the first key in the index.
+
+ @details
+ Called from opt_range.cc, opt_sum.cc, sql_handler.cc, and sql_select.cc.
+
+ @see
+ opt_range.cc, opt_sum.cc, sql_handler.cc and sql_select.cc
+*/
+int ha_connect::index_first(uchar *buf)
+{
+ int rc;
+ DBUG_ENTER("ha_connect::index_first");
+
+ if (indexing > 0)
+ rc= ReadIndexed(buf, OP_FIRST);
+ else if (indexing < 0)
+ rc= HA_ERR_INTERNAL_ERROR;
+ else if (CntRewindTable(xp->g, tdbp)) {
+ table->status= STATUS_NOT_FOUND;
+ rc= HA_ERR_INTERNAL_ERROR;
+ } else
+ rc= rnd_next(buf);
+
+ DBUG_RETURN(rc);
+} // end of index_first
+
+
+/**
+ @brief
+ index_last() asks for the last key in the index.
+
+ @details
+ Called from opt_range.cc, opt_sum.cc, sql_handler.cc, and sql_select.cc.
+
+ @see
+ opt_range.cc, opt_sum.cc, sql_handler.cc and sql_select.cc
+*/
+int ha_connect::index_last(uchar *buf)
+{
+ DBUG_ENTER("ha_connect::index_last");
+ int rc;
+
+ if (indexing <= 0) {
+ rc= HA_ERR_INTERNAL_ERROR;
+ } else
+ rc= ReadIndexed(buf, OP_LAST);
+
+ DBUG_RETURN(rc);
+}
+
+
+/****************************************************************************/
+/* This is called to get more rows having the same index value. */
+/****************************************************************************/
+int ha_connect::index_next_same(uchar *buf, const uchar *key, uint keylen)
+{
+ int rc;
+ DBUG_ENTER("ha_connect::index_next_same");
+//statistic_increment(ha_read_next_count, &LOCK_status);
+
+ if (!indexing)
+ rc= rnd_next(buf);
+ else if (indexing > 0)
+ rc= ReadIndexed(buf, OP_SAME);
+ else
+ rc= HA_ERR_INTERNAL_ERROR;
+
+ DBUG_RETURN(rc);
+} // end of index_next_same
+
+
+/**
+ @brief
+ rnd_init() is called when the system wants the storage engine to do a table
+ scan. See the example in the introduction at the top of this file to see when
+ rnd_init() is called.
+
+ @details
+ Called from filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc,
+ and sql_update.cc.
+
+ @note
+ We always call open and extern_lock/start_stmt before comming here.
+
+ @see
+ filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc and sql_update.cc
+*/
+int ha_connect::rnd_init(bool scan)
+{
+ int rc;
+ PGLOBAL g= ((table && table->in_use) ? GetPlug(table->in_use, xp) :
+ (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)
+ htrc("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);
+
+ // Do not close the table if it was opened yet (locked?)
+ if (IsOpened()) {
+ if (tdbp->OpenDB(g)) // Rewind table
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+ else
+ DBUG_RETURN(0);
+
+ } else if (xp->CheckQuery(valid_query_id))
+ tdbp= NULL; // Not valid anymore
+
+ // When updating, to avoid skipped update, force the table
+ // handler to retrieve write-only fields to be able to compare
+ // records and detect data change.
+ if (xmod == MODE_UPDATE)
+ bitmap_union(table->read_set, table->write_set);
+
+ if ((rc= OpenTable(g, xmod == MODE_DELETE)))
+ DBUG_RETURN(rc);
+
+ xp->nrd= xp->fnd= xp->nfd= 0;
+ xp->tb1= my_interval_timer();
+ DBUG_RETURN(0);
+} // end of rnd_init
+
+/**
+ @brief
+ Not described.
+
+ @note
+ The previous version said:
+ Stop scanning of table. Note that this may be called several times during
+ execution of a sub select.
+ =====> This has been moved to external lock to avoid closing subselect tables.
+*/
+int ha_connect::rnd_end()
+{
+ int rc= 0;
+ DBUG_ENTER("ha_connect::rnd_end");
+
+ // If this is called by a later query, the table may have
+ // been already closed and the tdbp is not valid anymore.
+// if (tdbp && xp->last_query_id == valid_query_id)
+// rc= CloseTable(xp->g);
+
+ ds_mrr.dsmrr_close();
+ DBUG_RETURN(rc);
+} // end of rnd_end
+
+
+/**
+ @brief
+ This is called for each row of the table scan. When you run out of records
+ you should return HA_ERR_END_OF_FILE. Fill buff up with the row information.
+ The Field structure for the table is the key to getting data into buf
+ in a manner that will allow the server to understand it.
+
+ @details
+ Called from filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc,
+ and sql_update.cc.
+
+ @see
+ filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc and sql_update.cc
+*/
+int ha_connect::rnd_next(uchar *buf)
+{
+ int rc;
+ DBUG_ENTER("ha_connect::rnd_next");
+//statistic_increment(ha_read_rnd_next_count, &LOCK_status);
+
+ if (tdbp->GetMode() == MODE_ANY) {
+ // We will stop on next read
+ if (!stop) {
+ stop= true;
+ DBUG_RETURN(RC_OK);
+ } else
+ DBUG_RETURN(HA_ERR_END_OF_FILE);
+
+ } // endif Mode
+
+ switch (CntReadNext(xp->g, tdbp)) {
+ case RC_OK:
+ rc= MakeRecord((char*)buf);
+ break;
+ case RC_EF: // End of file
+ rc= HA_ERR_END_OF_FILE;
+ break;
+ case RC_NF: // Not found
+ rc= HA_ERR_RECORD_DELETED;
+ break;
+ default: // Read error
+ htrc("rnd_next CONNECT: %s\n", xp->g->Message);
+ rc= (records()) ? HA_ERR_INTERNAL_ERROR : HA_ERR_END_OF_FILE;
+ break;
+ } // endswitch RC
+
+ if (xtrace > 1 && (rc || !(xp->nrd++ % 16384))) {
+ ulonglong tb2= my_interval_timer();
+ double elapsed= (double) (tb2 - xp->tb1) / 1000000000ULL;
+ DBUG_PRINT("rnd_next", ("rc=%d nrd=%u fnd=%u nfd=%u sec=%.3lf\n",
+ rc, (uint)xp->nrd, (uint)xp->fnd,
+ (uint)xp->nfd, elapsed));
+ htrc("rnd_next: rc=%d nrd=%u fnd=%u nfd=%u sec=%.3lf\n",
+ rc, (uint)xp->nrd, (uint)xp->fnd,
+ (uint)xp->nfd, elapsed);
+ xp->tb1= tb2;
+ xp->fnd= xp->nfd= 0;
+ } // endif nrd
+
+ table->status= (!rc) ? 0 : STATUS_NOT_FOUND;
+ DBUG_RETURN(rc);
+} // end of rnd_next
+
+
+/**
+ @brief
+ position() is called after each call to rnd_next() if the data needs
+ to be ordered. You can do something like the following to store
+ the position:
+ @code
+ my_store_ptr(ref, ref_length, current_position);
+ @endcode
+
+ @details
+ The server uses ref to store data. ref_length in the above case is
+ the size needed to store current_position. ref is just a byte array
+ that the server will maintain. If you are using offsets to mark rows, then
+ current_position should be the offset. If it is a primary key like in
+ BDB, then it needs to be a primary key.
+
+ Called from filesort.cc, sql_select.cc, sql_delete.cc, and sql_update.cc.
+
+ @see
+ filesort.cc, sql_select.cc, sql_delete.cc and sql_update.cc
+*/
+void ha_connect::position(const uchar *record)
+{
+ DBUG_ENTER("ha_connect::position");
+//if (((PTDBASE)tdbp)->GetDef()->Indexable())
+ my_store_ptr(ref, ref_length, (my_off_t)((PTDBASE)tdbp)->GetRecpos());
+ DBUG_VOID_RETURN;
+} // end of position
+
+
+/**
+ @brief
+ This is like rnd_next, but you are given a position to use
+ to determine the row. The position will be of the type that you stored in
+ ref. You can use my_get_ptr(pos,ref_length) to retrieve whatever key
+ or position you saved when position() was called.
+
+ @details
+ Called from filesort.cc, records.cc, sql_insert.cc, sql_select.cc, and sql_update.cc.
+
+ @note
+ Is this really useful? It was never called even when sorting.
+
+ @see
+ filesort.cc, records.cc, sql_insert.cc, sql_select.cc and sql_update.cc
+*/
+int ha_connect::rnd_pos(uchar *buf, uchar *pos)
+{
+ int rc;
+ PTDBASE tp= (PTDBASE)tdbp;
+ DBUG_ENTER("ha_connect::rnd_pos");
+
+ if (!tp->SetRecpos(xp->g, (int)my_get_ptr(pos, ref_length)))
+ rc= rnd_next(buf);
+ else
+ rc= HA_ERR_KEY_NOT_FOUND;
+
+ DBUG_RETURN(rc);
+} // end of rnd_pos
+
+
+/**
+ @brief
+ ::info() is used to return information to the optimizer. See my_base.h for
+ the complete description.
+
+ @details
+ Currently this table handler doesn't implement most of the fields really needed.
+ SHOW also makes use of this data.
+
+ You will probably want to have the following in your code:
+ @code
+ if (records < 2)
+ records= 2;
+ @endcode
+ The reason is that the server will optimize for cases of only a single
+ record. If, in a table scan, you don't know the number of records, it
+ will probably be better to set records to two so you can return as many
+ records as you need. Along with records, a few more variables you may wish
+ to set are:
+ records
+ deleted
+ data_file_length
+ index_file_length
+ delete_length
+ check_time
+ Take a look at the public variables in handler.h for more information.
+
+ Called in filesort.cc, ha_heap.cc, item_sum.cc, opt_sum.cc, sql_delete.cc,
+ sql_delete.cc, sql_derived.cc, sql_select.cc, sql_select.cc, sql_select.cc,
+ sql_select.cc, sql_select.cc, sql_show.cc, sql_show.cc, sql_show.cc, sql_show.cc,
+ sql_table.cc, sql_union.cc, and sql_update.cc.
+
+ @see
+ filesort.cc, ha_heap.cc, item_sum.cc, opt_sum.cc, sql_delete.cc, sql_delete.cc,
+ sql_derived.cc, sql_select.cc, sql_select.cc, sql_select.cc, sql_select.cc,
+ sql_select.cc, sql_show.cc, sql_show.cc, sql_show.cc, sql_show.cc, sql_table.cc,
+ sql_union.cc and sql_update.cc
+*/
+int ha_connect::info(uint flag)
+{
+ bool pure= false;
+ PGLOBAL g= GetPlug((table) ? table->in_use : NULL, xp);
+
+ DBUG_ENTER("ha_connect::info");
+
+ if (xtrace)
+ htrc("%p In info: flag=%u valid_info=%d\n", this, flag, valid_info);
+
+ if (!valid_info) {
+ // tdbp must be available to get updated info
+ if (xp->CheckQuery(valid_query_id) || !tdbp) {
+ if (xmod == MODE_ANY || xmod == MODE_ALTER) {
+ // Pure info, not a query
+ pure= true;
+ xp->CheckCleanup();
+ } // endif xmod
+
+ tdbp= GetTDB(g);
+ } // endif tdbp
+
+ valid_info= CntInfo(g, tdbp, &xinfo);
+ } // endif valid_info
+
+ if (flag & HA_STATUS_VARIABLE) {
+ stats.records= xinfo.records;
+ stats.deleted= 0;
+ stats.data_file_length= xinfo.data_file_length;
+ stats.index_file_length= 0;
+ stats.delete_length= 0;
+ stats.check_time= 0;
+ stats.mean_rec_length= xinfo.mean_rec_length;
+ } // endif HA_STATUS_VARIABLE
+
+ if (flag & HA_STATUS_CONST) {
+ // This is imported from the previous handler and must be reconsidered
+ stats.max_data_file_length= 4294967295;
+ stats.max_index_file_length= 4398046510080;
+ stats.create_time= 0;
+ data_file_name= xinfo.data_file_name;
+ index_file_name= NULL;
+// sortkey= (uint) - 1; // Table is not sorted
+ ref_length= sizeof(int); // Pointer size to row
+ table->s->db_options_in_use= 03;
+ stats.block_size= 1024;
+ table->s->keys_in_use.set_prefix(table->s->keys);
+ table->s->keys_for_keyread= table->s->keys_in_use;
+// table->s->keys_for_keyread.subtract(table->s->read_only_keys);
+ table->s->db_record_offset= 0;
+ } // endif HA_STATUS_CONST
+
+ if (flag & HA_STATUS_ERRKEY) {
+ errkey= 0;
+ } // endif HA_STATUS_ERRKEY
+
+ if (flag & HA_STATUS_TIME)
+ stats.update_time= 0;
+
+ if (flag & HA_STATUS_AUTO)
+ stats.auto_increment_value= 1;
+
+ if (tdbp && pure)
+ CloseTable(g); // Not used anymore
+
+ DBUG_RETURN(0);
+} // end of info
+
+
+/**
+ @brief
+ extra() is called whenever the server wishes to send a hint to
+ the storage engine. The myisam engine implements the most hints.
+ ha_innodb.cc has the most exhaustive list of these hints.
+
+ @note
+ This is not yet implemented for CONNECT.
+
+ @see
+ ha_innodb.cc
+*/
+int ha_connect::extra(enum ha_extra_function operation)
+{
+ DBUG_ENTER("ha_connect::extra");
+ DBUG_RETURN(0);
+} // end of extra
+
+
+/**
+ @brief
+ Used to delete all rows in a table, including cases of truncate and cases where
+ the optimizer realizes that all rows will be removed as a result of an SQL statement.
+
+ @details
+ Called from item_sum.cc by Item_func_group_concat::clear(),
+ Item_sum_count_distinct::clear(), and Item_func_group_concat::clear().
+ Called from sql_delete.cc by mysql_delete().
+ Called from sql_select.cc by JOIN::reinit().
+ Called from sql_union.cc by st_select_lex_unit::exec().
+
+ @see
+ Item_func_group_concat::clear(), Item_sum_count_distinct::clear() and
+ Item_func_group_concat::clear() in item_sum.cc;
+ mysql_delete() in sql_delete.cc;
+ JOIN::reinit() in sql_select.cc and
+ st_select_lex_unit::exec() in sql_union.cc.
+*/
+int ha_connect::delete_all_rows()
+{
+ int rc= 0;
+ PGLOBAL g= xp->g;
+ DBUG_ENTER("ha_connect::delete_all_rows");
+
+ if (tdbp && tdbp->GetUse() == USE_OPEN &&
+ tdbp->GetAmType() != TYPE_AM_XML &&
+ ((PTDBASE)tdbp)->GetFtype() != RECFM_NAF)
+ // Close and reopen the table so it will be deleted
+ rc= CloseTable(g);
+
+ if (!(rc= OpenTable(g))) {
+ if (CntDeleteRow(g, tdbp, true)) {
+ htrc("%s\n", g->Message);
+ rc= HA_ERR_INTERNAL_ERROR;
+ } // endif
+
+ } // endif rc
+
+ DBUG_RETURN(rc);
+} // end of 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);
+
+ switch (type) {
+ case TAB_UNDEF:
+// case TAB_CATLG:
+ case TAB_PLG:
+ case TAB_JCT:
+ case TAB_DMY:
+ case TAB_NIY:
+ my_printf_error(ER_UNKNOWN_ERROR,
+ "Unsupported table type %s", MYF(0), options->type);
+ return true;
+
+ case TAB_DOS:
+ case TAB_FIX:
+ case TAB_BIN:
+ case TAB_CSV:
+ case TAB_FMT:
+ case TAB_DBF:
+ case TAB_XML:
+ case TAB_INI:
+ case TAB_VEC:
+ 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;
+
+ /* Fall through to check FILE_ACL */
+ case TAB_ODBC:
+ case TAB_MYSQL:
+ case TAB_DIR:
+ case TAB_MAC:
+ case TAB_WMI:
+ case TAB_OEM:
+ return check_access(thd, FILE_ACL, db, NULL, NULL, 0, 0);
+
+ // This is temporary until a solution is found
+ case TAB_TBL:
+ case TAB_XCL:
+ case TAB_PRX:
+ case TAB_OCCUR:
+ case TAB_PIVOT:
+ return false;
+ } // endswitch type
+
+ my_printf_error(ER_UNKNOWN_ERROR, "check_privileges failed", MYF(0));
+ return true;
+} // end of check_privileges
+
+// Check that two indexes are equivalent
+bool ha_connect::IsSameIndex(PIXDEF xp1, PIXDEF xp2)
+{
+ bool b= true;
+ PKPDEF kp1, kp2;
+
+ if (stricmp(xp1->Name, xp2->Name))
+ b= false;
+ else if (xp1->Nparts != xp2->Nparts ||
+ xp1->MaxSame != xp2->MaxSame ||
+ xp1->Unique != xp2->Unique)
+ b= false;
+ else for (kp1= xp1->ToKeyParts, kp2= xp2->ToKeyParts;
+ b && (kp1 || kp2);
+ kp1= kp1->Next, kp2= kp2->Next)
+ if (!kp1 || !kp2)
+ b= false;
+ else if (stricmp(kp1->Name, kp2->Name))
+ b= false;
+ else if (kp1->Klen != kp2->Klen)
+ b= false;
+
+ return b;
+} // end of IsSameIndex
+
+MODE ha_connect::CheckMode(PGLOBAL g, THD *thd,
+ MODE newmode, bool *chk, bool *cras)
+{
+ if ((trace= xtrace)) {
+ LEX_STRING *query_string= thd_query_string(thd);
+ htrc("%p check_mode: cmdtype=%d\n", this, thd_sql_command(thd));
+ htrc("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:
+ 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;
+ case SQLCOM_ALTER_TABLE:
+ newmode= MODE_ALTER;
+ break;
+ default:
+ htrc("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:
+ *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;
+ case SQLCOM_ALTER_TABLE:
+ *chk= true;
+ newmode= MODE_ALTER;
+ break;
+ default:
+ htrc("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)
+ htrc("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
+ that can handle transacations look at ha_berkely.cc to see how you will
+ want to go about doing this. Otherwise you should consider calling flock()
+ here. Hint: Read the section "locking functions for mysql" in lock.cc to understand
+ this.
+
+ @details
+ Called from lock.cc by lock_external() and unlock_external(). Also called
+ from sql_table.cc by copy_data_between_tables().
+
+ @note
+ Following what we did in the MySQL XDB handler, we use this call to actually
+ physically open the table. This could be reconsider when finalizing this handler
+ design, which means we have a better understanding of what MariaDB does.
+
+ @see
+ lock.cc by lock_external() and unlock_external() in lock.cc;
+ the section "locking functions for mysql" in lock.cc;
+ copy_data_between_tables() in sql_table.cc.
+*/
+int ha_connect::external_lock(THD *thd, int lock_type)
+{
+ int rc= 0;
+ bool xcheck=false, cras= false;
+ MODE newmode;
+ PTOS options= GetTableOptionStruct(table);
+ PGLOBAL g= GetPlug(thd, xp);
+ DBUG_ENTER("ha_connect::external_lock");
+
+ DBUG_ASSERT(thd == current_thd);
+
+ if (xtrace)
+ htrc("external_lock: this=%p thd=%p xp=%p g=%p lock_type=%d\n",
+ this, thd, xp, g, lock_type);
+
+ if (!g)
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+
+ // Action will depend on lock_type
+ switch (lock_type) {
+ case F_WRLCK:
+ newmode= MODE_WRITE;
+ break;
+ case F_RDLCK:
+ newmode= MODE_READ;
+ break;
+ case F_UNLCK:
+ default:
+ newmode= MODE_ANY;
+ break;
+ } // endswitch mode
+
+ if (newmode == MODE_ANY) {
+ int sqlcom= thd_sql_command(thd);
+
+ // This is unlocking, do it by closing the table
+ if (xp->CheckQueryID() && sqlcom != SQLCOM_UNLOCK_TABLES
+ && sqlcom != SQLCOM_LOCK_TABLES
+ && sqlcom != SQLCOM_DROP_TABLE) {
+ sprintf(g->Message, "external_lock: unexpected command %d", sqlcom);
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
+ DBUG_RETURN(0);
+ } 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());
+// DBUG_RETURN(HA_ERR_INTERNAL_ERROR); causes assert error
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
+ DBUG_RETURN(0);
+ } // endif Indexable
+
+ bool oldsep= ((PCHK)g->Xchk)->oldsep;
+ bool newsep= ((PCHK)g->Xchk)->newsep;
+ PTDBDOS tdp= (PTDBDOS)tdbp;
+
+ PDOSDEF ddp= (PDOSDEF)tdp->GetDef();
+ PIXDEF xp, xp1, xp2, drp=NULL, adp= NULL;
+ PIXDEF oldpix= ((PCHK)g->Xchk)->oldpix;
+ PIXDEF newpix= ((PCHK)g->Xchk)->newpix;
+ PIXDEF *xlst, *xprc;
+
+ ddp->SetIndx(oldpix);
+
+ if (oldsep != newsep) {
+ // All indexes have to be remade
+ ddp->DeleteIndexFile(g, NULL);
+ oldpix= NULL;
+ ddp->SetIndx(NULL);
+ SetBooleanOption("Sepindex", newsep);
+ } else if (newsep) {
+ // Make the list of dropped indexes
+ xlst= &drp; xprc= &oldpix;
+
+ for (xp2= oldpix; xp2; xp2= xp) {
+ for (xp1= newpix; xp1; xp1= xp1->Next)
+ if (IsSameIndex(xp1, xp2))
+ break; // Index not to drop
+
+ xp= xp2->GetNext();
+
+ if (!xp1) {
+ *xlst= xp2;
+ *xprc= xp;
+ *(xlst= &xp2->Next)= NULL;
+ } else
+ xprc= &xp2->Next;
+
+ } // endfor xp2
+
+ if (drp) {
+ // Here we erase the index files
+ ddp->DeleteIndexFile(g, drp);
+ } // endif xp1
+
+ } else if (oldpix) {
+ // TODO: optimize the case of just adding new indexes
+ if (!newpix)
+ ddp->DeleteIndexFile(g, NULL);
+
+ oldpix= NULL; // To remake all indexes
+ ddp->SetIndx(NULL);
+ } // endif sepindex
+
+ // Make the list of new created indexes
+ xlst= &adp; xprc= &newpix;
+
+ for (xp1= newpix; xp1; xp1= xp) {
+ for (xp2= oldpix; xp2; xp2= xp2->Next)
+ if (IsSameIndex(xp1, xp2))
+ break; // Index already made
+
+ xp= xp1->Next;
+
+ if (!xp2) {
+ *xlst= xp1;
+ *xprc= xp;
+ *(xlst= &xp1->Next)= NULL;
+ } else
+ xprc= &xp1->Next;
+
+ } // endfor xp1
+
+ if (adp)
+ // Here we do make the new indexes
+ if (tdp->MakeIndex(g, adp, true) == RC_FX) {
+ // Make it a warning to avoid crash
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
+ 0, g->Message);
+ rc= 0;
+ } // endif MakeIndex
+
+ } // endif Tdbp
+
+ } // endelse Xchk
+
+ if (CloseTable(g)) {
+ // This is an error while builing index
+ // Make it a warning to avoid crash
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
+ rc= 0;
+ } // endif Close
+
+ locked= 0;
+ DBUG_RETURN(rc);
+ } // endif MODE_ANY
+
+ DBUG_ASSERT(table && table->s);
+
+ if (check_privileges(thd, options, table->s->db.str)) {
+ strcpy(g->Message, "This operation requires the FILE privilege");
+ htrc("%s\n", g->Message);
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+ } // endif check_privileges
+
+ // Table mode depends on the query type
+ newmode= CheckMode(g, thd, newmode, &xcheck, &cras);
+
+ 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()) {
+ tdbp= NULL;
+ valid_info= false;
+ } // endif CheckCleanup
+
+#if 0
+ if (xcheck) {
+ // This must occur after CheckCleanup
+ 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) {
+#if 0
+ htrc("xcheck=%d cras=%d\n", xcheck, cras);
+
+ if (xcheck)
+ htrc("oldsep=%d oldpix=%p\n",
+ ((PCHK)g->Xchk)->oldsep, ((PCHK)g->Xchk)->oldpix);
+#endif // 0
+ htrc("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))) {
+ htrc("%p external_lock: %s\n", this, g->Message);
+ rc= HA_ERR_INTERNAL_ERROR;
+ // This can NOT be called without open called first, but
+ // the table can have been closed since then
+ } else if (!tdbp || xp->CheckQuery(valid_query_id) || xmod != newmode) {
+ if (tdbp) {
+ // If this is called by a later query, the table may have
+ // been already closed and the tdbp is not valid anymore.
+ if (xp->last_query_id == valid_query_id)
+ rc= CloseTable(g);
+ else
+ tdbp= NULL;
+
+ } // endif tdbp
+
+ xmod= newmode;
+
+ // Delay open until used fields are known
+ } // endif tdbp
+
+ if (xtrace)
+ htrc("external_lock: rc=%d\n", rc);
+
+ DBUG_RETURN(rc);
+} // end of external_lock
+
+
+/**
+ @brief
+ The idea with handler::store_lock() is: The statement decides which locks
+ should be needed for the table. For updates/deletes/inserts we get WRITE
+ locks, for SELECT... we get read locks.
+
+ @details
+ Before adding the lock into the table lock handler (see thr_lock.c),
+ mysqld calls store lock with the requested locks. Store lock can now
+ modify a write lock to a read lock (or some other lock), ignore the
+ lock (if we don't want to use MySQL table locks at all), or add locks
+ for many tables (like we do when we are using a MERGE handler).
+
+ Berkeley DB, for example, changes all WRITE locks to TL_WRITE_ALLOW_WRITE
+ (which signals that we are doing WRITES, but are still allowing other
+ readers and writers).
+
+ When releasing locks, store_lock() is also called. In this case one
+ usually doesn't have to do anything.
+
+ In some exceptional cases MySQL may send a request for a TL_IGNORE;
+ This means that we are requesting the same lock as last time and this
+ should also be ignored. (This may happen when someone does a flush
+ table when we have opened a part of the tables, in which case mysqld
+ closes and reopens the tables and tries to get the same locks at last
+ time). In the future we will probably try to remove this.
+
+ Called from lock.cc by get_lock_data().
+
+ @note
+ In this method one should NEVER rely on table->in_use, it may, in fact,
+ refer to a different thread! (this happens if get_lock_data() is called
+ from mysql_lock_abort_for_thread() function)
+
+ @see
+ get_lock_data() in lock.cc
+*/
+THR_LOCK_DATA **ha_connect::store_lock(THD *thd,
+ THR_LOCK_DATA **to,
+ enum thr_lock_type lock_type)
+{
+ if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK)
+ lock.type=lock_type;
+ *to++ = &lock;
+ return to;
+}
+
+
+/**
+ Searches for a pointer to the last occurrence of the
+ character c in the string src.
+ Returns true on failure, false on success.
+*/
+static bool
+strnrchr(LEX_CSTRING *ls, const char *src, size_t length, int c)
+{
+ const char *srcend, *s;
+ for (s= srcend= src + length; s > src; s--)
+ {
+ if (s[-1] == c)
+ {
+ ls->str= s;
+ ls->length= srcend - s;
+ return false;
+ }
+ }
+ return true;
+}
+
+
+/**
+ Split filename into database and table name.
+*/
+static bool
+filename_to_dbname_and_tablename(const char *filename,
+ char *database, size_t database_size,
+ char *table, size_t table_size)
+{
+#if defined(WIN32)
+ char slash= '\\';
+#else // !WIN32
+ char slash= '/';
+#endif // !WIN32
+ LEX_CSTRING d, t;
+ size_t length= strlen(filename);
+
+ /* Find filename - the rightmost directory part */
+ if (strnrchr(&t, filename, length, slash) || t.length + 1 > table_size)
+ return true;
+ memcpy(table, t.str, t.length);
+ table[t.length]= '\0';
+ if (!(length-= t.length))
+ return true;
+
+ length--; /* Skip slash */
+
+ /* Find database name - the second rightmost directory part */
+ if (strnrchr(&d, filename, length, slash) || d.length + 1 > database_size)
+ return true;
+ memcpy(database, d.str, d.length);
+ database[d.length]= '\0';
+ return false;
+} // end of filename_to_dbname_and_tablename
+
+/**
+ @brief
+ Used to delete or rename a table. By the time delete_table() has been
+ called all opened references to this table will have been closed
+ (and your globally shared references released) ===> too bad!!!
+ The variable name will just be the name of the table.
+ You will need to remove or rename any files you have created at
+ this point.
+
+ @details
+ If you do not implement this, the default delete_table() is called from
+ handler.cc and it will delete all files with the file extensions returned
+ by bas_ext().
+
+ Called from handler.cc by delete_table and ha_create_table(). Only used
+ during create if the table_flag HA_DROP_BEFORE_CREATE was specified for
+ the storage engine.
+
+ @see
+ delete_table and ha_create_table() in handler.cc
+*/
+int ha_connect::delete_or_rename_table(const char *name, const char *to)
+{
+ DBUG_ENTER("ha_connect::delete_or_rename_table");
+ 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)
+ htrc("rename_table: this=%p thd=%p sqlcom=%d from=%s to=%s\n",
+ this, thd, sqlcom, name, to);
+ else
+ htrc("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 == '#' && sqlcom == SQLCOM_CREATE_INDEX)))
+ DBUG_RETURN(0);
+
+ if (filename_to_dbname_and_tablename(name, db, sizeof(db),
+ tabname, sizeof(tabname))
+ || (*tabname == '#' && sqlcom == SQLCOM_CREATE_INDEX))
+ DBUG_RETURN(0);
+
+ // 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;
+
+ key_length= tdc_create_key(key, db, tabname);
+
+ // share contains the option struct that we need
+ if (!(share= alloc_table_share(db, tabname, key, key_length)))
+ DBUG_RETURN(rc);
+
+#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();
+
+ free_table_share(share);
+ } else // Temporary file
+ ok= true;
+
+ if (ok) {
+ // Let the base handler do the job
+ if (to)
+ rc= handler::rename_table(name, to);
+ else if ((rc= handler::delete_table(name)) == ENOENT)
+ rc= 0; // No files is not an error for CONNECT
+
+ } // endif ok
+
+ DBUG_RETURN(rc);
+} // end of delete_or_rename_table
+
+int ha_connect::delete_table(const char *name)
+{
+ return delete_or_rename_table(name, NULL);
+} // end of delete_table
+
+int ha_connect::rename_table(const char *from, const char *to)
+{
+ return delete_or_rename_table(from, to);
+} // end of rename_table
+
+/**
+ @brief
+ Given a starting key and an ending key, estimate the number of rows that
+ will exist between the two keys.
+
+ @details
+ end_key may be empty, in which case determine if start_key matches any rows.
+
+ Called from opt_range.cc by check_quick_keys().
+
+ @see
+ check_quick_keys() in opt_range.cc
+*/
+ha_rows ha_connect::records_in_range(uint inx, key_range *min_key,
+ key_range *max_key)
+{
+ ha_rows rows;
+ DBUG_ENTER("ha_connect::records_in_range");
+
+ if (indexing < 0 || inx != active_index)
+ index_init(inx, false);
+
+ if (xtrace)
+ htrc("records_in_range: inx=%d indexing=%d\n", inx, indexing);
+
+ if (indexing > 0) {
+ int nval;
+ uint len[2];
+ const uchar *key[2];
+ bool incl[2];
+ key_part_map kmap[2];
+
+ key[0]= (min_key) ? min_key->key : NULL;
+ key[1]= (max_key) ? max_key->key : NULL;
+ len[0]= (min_key) ? min_key->length : 0;
+ len[1]= (max_key) ? max_key->length : 0;
+ incl[0]= (min_key) ? (min_key->flag == HA_READ_KEY_EXACT) : false;
+ incl[1]= (max_key) ? (max_key->flag == HA_READ_AFTER_KEY) : false;
+ kmap[0]= (min_key) ? min_key->keypart_map : 0;
+ kmap[1]= (max_key) ? max_key->keypart_map : 0;
+
+ if ((nval= CntIndexRange(xp->g, tdbp, key, len, incl, kmap)) < 0)
+ rows= HA_POS_ERROR;
+ else
+ rows= (ha_rows)nval;
+
+ } else if (indexing < 0)
+ rows= HA_POS_ERROR;
+ else
+ rows= 100000000; // Don't use missing index
+
+ DBUG_RETURN(rows);
+} // end of records_in_range
+
+/**
+ Convert an ISO-8859-1 column name to UTF-8
+*/
+static char *encode(PGLOBAL g, char *cnm)
+ {
+ char *buf= (char*)PlugSubAlloc(g, NULL, strlen(cnm) * 3);
+ uint dummy_errors;
+ uint32 len= copy_and_convert(buf, strlen(cnm) * 3,
+ &my_charset_utf8_general_ci,
+ cnm, strlen(cnm),
+ &my_charset_latin1,
+ &dummy_errors);
+ buf[len]= '\0';
+ return buf;
+ } // end of Encode
+
+/**
+ Store field definition for create.
+
+ @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,
+ char v)
+{
+ register Create_field *new_field;
+ char *length, *decimals= NULL;
+ enum_field_types type;
+//Virtual_column_info *vcol_info= (Virtual_column_info *)vcolinfo;
+ engine_option_value *crop;
+ LEX_STRING *comment;
+ LEX_STRING *field_name;
+
+ DBUG_ENTER("ha_connect::add_fields");
+
+ if (len) {
+ if (!v && typ == TYPE_STRING && len > 255)
+ v= 'V'; // Change CHAR to VARCHAR
+
+ length= (char*)PlugSubAlloc(g, NULL, 8);
+ sprintf(length, "%d", len);
+
+ if (typ == TYPE_DOUBLE) {
+ decimals= (char*)PlugSubAlloc(g, NULL, 8);
+ sprintf(decimals, "%d", min(dec, (min(len, 31) - 1)));
+ } // endif dec
+
+ } else
+ length= NULL;
+
+ if (!rem)
+ rem= "";
+
+ type= PLGtoMYSQL(typ, dbf, v);
+ comment= thd->make_lex_string(rem, strlen(rem));
+ field_name= thd->make_lex_string(name, strlen(name));
+
+ switch (v) {
+ case 'Z': type_modifier|= ZEROFILL_FLAG;
+ case 'U': type_modifier|= UNSIGNED_FLAG; break;
+ } // endswitch v
+
+ 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,
+ char *dft, char *xtra, int flag, bool dbf, char v)
+{
+ char var = (len > 255) ? 'V' : v;
+ bool error= false;
+ const char *type= PLGtoMYSQLtype(typ, dbf, var);
+
+ error|= sql->append('`');
+ error|= sql->append(field_name);
+ error|= sql->append("` ");
+ error|= sql->append(type);
+
+ if (len && typ != TYPE_DATE) {
+ error|= sql->append('(');
+ error|= sql->append_ulonglong(len);
+
+ if (!strcmp(type, "DOUBLE")) {
+ error|= sql->append(',');
+ // dec must be < len and < 31
+ error|= sql->append_ulonglong(min(dec, (min(len, 31) - 1)));
+ } else if (dec > 0 && !strcmp(type, "DECIMAL")) {
+ error|= sql->append(',');
+ // dec must be < len
+ error|= sql->append_ulonglong(min(dec, len - 1));
+ } // endif dec
+
+ error|= sql->append(')');
+ } // endif len
+
+ if (v == 'U')
+ error|= sql->append(" UNSIGNED");
+ else if (v == 'Z')
+ error|= sql->append(" ZEROFILL");
+
+ if (tm)
+ error|= sql->append(STRING_WITH_LEN(" NOT NULL"), system_charset_info);
+
+ if (dft && *dft) {
+ error|= sql->append(" DEFAULT ");
+
+ if (!IsTypeNum(typ)) {
+ error|= sql->append("'");
+ error|= sql->append_for_single_quote(dft, strlen(dft));
+ error|= sql->append("'");
+ } else
+ error|= sql->append(dft);
+
+ } // endif dft
+
+ if (xtra && *xtra) {
+ error|= sql->append(" ");
+ error|= sql->append(xtra);
+ } // endif rem
+
+ if (rem && *rem) {
+ error|= sql->append(" COMMENT '");
+ error|= sql->append_for_single_quote(rem, strlen(rem));
+ error|= sql->append("'");
+ } // endif rem
+
+ if (flag) {
+ error|= sql->append(" FLAG=");
+ error|= sql->append_ulonglong(flag);
+ } // endif flag
+
+ 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)
+{
+ KEY *not_used_1;
+ uint not_used_2;
+ 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, C_ORDINARY_CREATE,
+ &not_used_1, &not_used_2, &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<uchar*>(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,
+// char *dsn,
+ 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) {
+//if (dsn) {
+ 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_for_single_quote(dsn, strlen(dsn));
+ 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
+
+// Used to check whether a MYSQL table is created on itself
+static bool CheckSelf(PGLOBAL g, TABLE_SHARE *s, const char *host,
+ const char *db, char *tab, const char *src, int port)
+{
+ if (src)
+ return false;
+ else if (host && stricmp(host, "localhost") && strcmp(host, "127.0.0.1"))
+ return false;
+ else if (db && stricmp(db, s->db.str))
+ return false;
+ else if (tab && stricmp(tab, s->table_name.str))
+ return false;
+ else if (port && port != (signed)GetDefaultPort())
+ return false;
+
+ strcpy(g->Message, "This MySQL table is defined on itself");
+ return true;
+} // end of CheckSelf
+
+/**
+ @brief
+ connect_assisted_discovery() is called when creating a table with no columns.
+
+ @details
+ 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,
+ HA_CREATE_INFO *create_info)
+{
+ char v, spc= ',', qch= 0;
+ const char *fncn= "?";
+ const char *user, *fn, *db, *host, *pwd, *sep, *tbl, *src;
+ const char *col, *ocl, *rnk, *pic, *fcl;
+ char *tab, *dsn, *shm;
+#if defined(WIN32)
+ char *nsp= NULL, *cls= NULL;
+#endif // WIN32
+ int port= 0, hdr= 0, mxr __attribute__((unused))= 0, mxe= 0, rc= 0;
+ int cop __attribute__((unused)) = 0;
+ uint tm, fnc= FNC_NO, supfnc= (FNC_NO | FNC_COL);
+ bool bif, ok= false, dbf= false;
+ TABTYPE ttp= TAB_UNDEF;
+ PQRYRES qrp= NULL;
+ PCOLRES crp;
+ PCONNECT xp= NULL;
+ PGLOBAL g= GetPlug(thd, xp);
+ PDBUSER dup= PlgGetUser(g);
+ PCATLG cat= (dup) ? dup->Catalog : 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;
+
+ user= host= pwd= tbl= src= col= ocl= pic= fcl= rnk= dsn= NULL;
+
+ // Get the useful create options
+ ttp= GetTypeID(topt->type);
+ fn= topt->filename;
+ tab= (char*)topt->tabname;
+ src= topt->srcdef;
+ db= topt->dbname;
+ fncn= topt->catfunc;
+ fnc= GetFuncID(fncn);
+ sep= topt->separator;
+ spc= (!sep || !strcmp(sep, "\\t")) ? '\t' : *sep;
+ qch= topt->qchar ? *topt->qchar : (signed)topt->quoted >= 0 ? '"' : 0;
+ hdr= (int)topt->header;
+ tbl= topt->tablist;
+ col= topt->colist;
+
+ if (topt->oplist) {
+ host= GetListOption(g, "host", topt->oplist, "localhost");
+ user= GetListOption(g, "user", topt->oplist, "root");
+ // Default value db can come from the DBNAME=xxx option.
+ db= GetListOption(g, "database", topt->oplist, db);
+ col= GetListOption(g, "colist", topt->oplist, col);
+ ocl= GetListOption(g, "occurcol", topt->oplist, NULL);
+ pic= GetListOption(g, "pivotcol", topt->oplist, NULL);
+ fcl= GetListOption(g, "fnccol", topt->oplist, NULL);
+ rnk= GetListOption(g, "rankcol", topt->oplist, NULL);
+ pwd= GetListOption(g, "password", topt->oplist);
+#if defined(WIN32)
+ nsp= GetListOption(g, "namespace", topt->oplist);
+ cls= GetListOption(g, "class", topt->oplist);
+#endif // WIN32
+ port= atoi(GetListOption(g, "port", topt->oplist, "0"));
+ mxr= atoi(GetListOption(g,"maxres", topt->oplist, "0"));
+ mxe= atoi(GetListOption(g,"maxerr", topt->oplist, "0"));
+#if defined(PROMPT_OK)
+ cop= atoi(GetListOption(g, "checkdsn", topt->oplist, "0"));
+#endif // PROMPT_OK
+ } else {
+ host= "localhost";
+ user= "root";
+ } // endif option_list
+
+ if (!(shm= (char*)db))
+ db= table_s->db.str; // Default value
+
+ // Check table type
+ if (ttp == TAB_UNDEF) {
+ topt->type= (src) ? "MYSQL" : (tab) ? "PROXY" : "DOS";
+ ttp= GetTypeID(topt->type);
+ sprintf(g->Message, "No table_type. Was set to %s", topt->type);
+ push_warning(thd, 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));
+ return HA_ERR_INTERNAL_ERROR;
+ } // endif ttp
+
+ if (!tab) {
+ if (ttp == TAB_TBL) {
+ // Make tab the first table of the list
+ char *p;
+
+ if (!tbl) {
+ strcpy(g->Message, "Missing table list");
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ return HA_ERR_INTERNAL_ERROR;
+ } // endif tbl
+
+ tab= (char*)PlugSubAlloc(g, NULL, strlen(tbl) + 1);
+ strcpy(tab, tbl);
+
+ if ((p= strchr(tab, ',')))
+ *p= 0;
+
+ if ((p=strchr(tab, '.'))) {
+ *p= 0;
+ db= tab;
+ tab= p + 1;
+ } // endif p
+
+ } else if (ttp != TAB_ODBC || !(fnc & (FNC_TABLE | FNC_COL)))
+ tab= table_s->table_name.str; // Default value
+
+#if defined(NEW_WAY)
+// add_option(thd, create_info, "tabname", tab);
+#endif // NEW_WAY
+ } // endif tab
+
+ switch (ttp) {
+#if defined(ODBC_SUPPORT)
+ case TAB_ODBC:
+ dsn= create_info->connect_string.str;
+
+ if (fnc & (FNC_DSN | FNC_DRIVER)) {
+ ok= true;
+#if defined(PROMPT_OK)
+ } else if (!stricmp(thd->main_security_ctx.host, "localhost")
+ && cop == 1) {
+ if ((dsn = ODBCCheckConnection(g, dsn, cop)) != NULL) {
+ thd->make_lex_string(&create_info->connect_string, dsn, strlen(dsn));
+ ok= true;
+ } // endif dsn
+#endif // PROMPT_OK
+
+ } else if (!dsn)
+ sprintf(g->Message, "Missing %s connection string", topt->type);
+ else
+ ok= true;
+
+ supfnc |= (FNC_TABLE | FNC_DSN | FNC_DRIVER);
+ break;
+#endif // ODBC_SUPPORT
+ case TAB_DBF:
+ dbf= true;
+ // Passthru
+ case TAB_CSV:
+ if (!fn && fnc != FNC_NO)
+ sprintf(g->Message, "Missing %s file name", topt->type);
+ else
+ ok= true;
+
+ break;
+#if defined(MYSQL_SUPPORT)
+ case TAB_MYSQL:
+ ok= true;
+
+ if (create_info->connect_string.str) {
+ int len= create_info->connect_string.length;
+ PMYDEF mydef= new(g) MYSQLDEF();
+
+ dsn= (char*)PlugSubAlloc(g, NULL, len + 1);
+ strncpy(dsn, create_info->connect_string.str, len);
+ dsn[len]= 0;
+ mydef->SetName(create_info->alias);
+ mydef->SetCat(cat);
+
+ if (!mydef->ParseURL(g, dsn, false)) {
+ if (mydef->GetHostname())
+ host= mydef->GetHostname();
+
+ if (mydef->GetUsername())
+ user= mydef->GetUsername();
+
+ if (mydef->GetPassword())
+ pwd= mydef->GetPassword();
+
+ if (mydef->GetDatabase())
+ db= mydef->GetDatabase();
+
+ if (mydef->GetTabname())
+ tab= mydef->GetTabname();
+
+ if (mydef->GetPortnumber())
+ port= mydef->GetPortnumber();
+
+ } else
+ ok= false;
+
+ } else if (!user)
+ user= "root";
+
+ if (CheckSelf(g, table_s, host, db, tab, src, port))
+ ok= false;
+
+ break;
+#endif // MYSQL_SUPPORT
+#if defined(WIN32)
+ case TAB_WMI:
+ ok= true;
+ break;
+#endif // WIN32
+ case TAB_PIVOT:
+ supfnc= FNC_NO;
+ case TAB_PRX:
+ case TAB_TBL:
+ case TAB_XCL:
+ case TAB_OCCUR:
+ if (!src && !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;
+ 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);
+ break;
+ } // endif ttp
+
+ // Check for supported catalog function
+ if (ok && !(supfnc & fnc)) {
+ sprintf(g->Message, "Unsupported catalog function %s for table type %s",
+ fncn, topt->type);
+ ok= false;
+ } // endif supfnc
+
+ if (src && fnc != FNC_NO) {
+ strcpy(g->Message, "Cannot make catalog table from srcdef");
+ ok= false;
+ } // endif src
+
+ if (ok) {
+ char *cnm, *rem, *dft, *xtra;
+ int i, len, prec, dec, typ, flg;
+
+ if (cat)
+ cat->SetDataPath(g, table_s->db.str);
+ else
+ return HA_ERR_INTERNAL_ERROR; // Should never happen
+
+ if (src && ttp != TAB_PIVOT && ttp != TAB_ODBC) {
+ qrp= SrcColumns(g, host, db, user, pwd, src, port);
+
+ if (qrp && ttp == TAB_OCCUR)
+ if (OcrSrcCols(g, qrp, col, ocl, rnk)) {
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ return HA_ERR_INTERNAL_ERROR;
+ } // endif OcrSrcCols
+
+ } else switch (ttp) {
+ case TAB_DBF:
+ qrp= DBFColumns(g, fn, fnc == FNC_COL);
+ break;
+#if defined(ODBC_SUPPORT)
+ case TAB_ODBC:
+ switch (fnc) {
+ case FNC_NO:
+ case FNC_COL:
+ if (src) {
+ qrp= ODBCSrcCols(g, dsn, (char*)src);
+ src= NULL; // for next tests
+ } else
+ qrp= ODBCColumns(g, dsn, shm, tab, NULL, mxr, fnc == FNC_COL);
+
+ break;
+ case FNC_TABLE:
+ qrp= ODBCTables(g, dsn, shm, tab, mxr, true);
+ break;
+ case FNC_DSN:
+ qrp= ODBCDataSources(g, mxr, true);
+ break;
+ case FNC_DRIVER:
+ qrp= ODBCDrivers(g, mxr, true);
+ break;
+ default:
+ sprintf(g->Message, "invalid catfunc %s", fncn);
+ break;
+ } // endswitch info
+
+ break;
+#endif // ODBC_SUPPORT
+#if defined(MYSQL_SUPPORT)
+ case TAB_MYSQL:
+ qrp= MyColumns(g, thd, host, db, user, pwd, tab,
+ NULL, port, fnc == FNC_COL);
+ break;
+#endif // MYSQL_SUPPORT
+ case TAB_CSV:
+ qrp= CSVColumns(g, fn, spc, qch, hdr, mxe, fnc == FNC_COL);
+ break;
+#if defined(WIN32)
+ case TAB_WMI:
+ qrp= WMIColumns(g, nsp, cls, fnc == FNC_COL);
+ break;
+#endif // WIN32
+ case TAB_PRX:
+ case TAB_TBL:
+ case TAB_XCL:
+ case TAB_OCCUR:
+ bif= fnc == FNC_COL;
+ qrp= TabColumns(g, thd, db, tab, bif);
+
+ if (!qrp && bif && fnc != FNC_COL) // tab is a view
+ qrp= MyColumns(g, thd, host, db, user, pwd, tab, NULL, port, false);
+
+ if (qrp && ttp == TAB_OCCUR && fnc != FNC_COL)
+ if (OcrColumns(g, qrp, col, ocl, rnk)) {
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ return HA_ERR_INTERNAL_ERROR;
+ } // endif OcrColumns
+
+ break;
+ case TAB_PIVOT:
+ qrp= PivotColumns(g, tab, src, pic, fcl, host, db, user, pwd, port);
+ break;
+ case TAB_OEM:
+ qrp= OEMColumns(g, topt, tab, (char*)db, fnc == FNC_COL);
+ break;
+ default:
+ strcpy(g->Message, "System error during assisted discovery");
+ break;
+ } // endswitch ttp
+
+ if (!qrp) {
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ return HA_ERR_INTERNAL_ERROR;
+ } // endif qrp
+
+ if (fnc != FNC_NO || src || ttp == TAB_PIVOT) {
+ // Catalog like table
+ for (crp= qrp->Colresp; !rc && crp; crp= crp->Next) {
+ cnm= encode(g, crp->Name);
+ typ= crp->Type;
+ len= crp->Length;
+ dec= crp->Prec;
+ flg= crp->Flag;
+ v= crp->Var;
+
+ if (!len && typ == TYPE_STRING)
+ len= 256; // STRBLK's have 0 length
+
+ // Now add the field
+#if defined(NEW_WAY)
+ rc= add_fields(g, thd, &alter_info, cnm, typ, len, dec,
+ NOT_NULL_FLAG, "", flg, dbf, v);
+#else // !NEW_WAY
+ if (add_field(&sql, cnm, typ, len, dec, NOT_NULL_FLAG,
+ NULL, NULL, NULL, flg, dbf, v))
+ rc= HA_ERR_OUT_OF_MEM;
+#endif // !NEW_WAY
+ } // endfor crp
+
+ } else // Not a catalog table
+ for (i= 0; !rc && i < qrp->Nblin; i++) {
+ typ= len= prec= dec= 0;
+ tm= NOT_NULL_FLAG;
+ cnm= (char*)"noname";
+ dft= xtra= NULL;
+#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) {
+ case FLD_NAME:
+ cnm= encode(g, crp->Kdata->GetCharValue(i));
+ break;
+ case FLD_TYPE:
+ typ= crp->Kdata->GetIntValue(i);
+ v = (crp->Nulls) ? crp->Nulls[i] : 0;
+ break;
+ case FLD_PREC:
+ // PREC must be always before LENGTH
+ len= prec= crp->Kdata->GetIntValue(i);
+ break;
+ case FLD_LENGTH:
+ len= crp->Kdata->GetIntValue(i);
+ break;
+ case FLD_SCALE:
+ dec= crp->Kdata->GetIntValue(i);
+ break;
+ case FLD_NULL:
+ if (crp->Kdata->GetIntValue(i))
+ tm= 0; // Nullable
+
+ break;
+ case FLD_REM:
+ rem= crp->Kdata->GetCharValue(i);
+ break;
+// case FLD_CHARSET:
+ // No good because remote table is already translated
+// if (*(csn= crp->Kdata->GetCharValue(i)))
+// cs= get_charset_by_name(csn, 0);
+
+// break;
+ case FLD_DEFAULT:
+ dft= crp->Kdata->GetCharValue(i);
+ break;
+ case FLD_EXTRA:
+ xtra= crp->Kdata->GetCharValue(i);
+
+ // Auto_increment is not supported yet
+ if (!stricmp(xtra, "AUTO_INCREMENT"))
+ xtra= NULL;
+
+ break;
+ default:
+ break; // Ignore
+ } // endswitch Fld
+
+#if defined(ODBC_SUPPORT)
+ if (ttp == TAB_ODBC) {
+ int plgtyp;
+
+ // typ must be PLG type, not SQL type
+ if (!(plgtyp= TranslateSQLType(typ, dec, prec, v))) {
+ sprintf(g->Message, "Unsupported SQL type %d", typ);
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ return HA_ERR_INTERNAL_ERROR;
+ } else
+ typ= plgtyp;
+
+ switch (typ) {
+ case TYPE_DOUBLE:
+ // Some data sources do not count dec in length (prec)
+ prec += (dec + 2); // To be safe
+ case TYPE_DECIM:
+ break;
+ default:
+ dec= 0;
+ } // endswitch typ
+
+ } // endif ttp
+#endif // ODBC_SUPPORT
+
+ // Make the arguments as required by add_fields
+ if (typ == TYPE_DATE)
+ prec= 0;
+ else if (typ == TYPE_DOUBLE)
+ prec= len;
+
+ // Now add the field
+#if defined(NEW_WAY)
+ rc= add_fields(g, thd, &alter_info, cnm, typ, prec, dec,
+ tm, rem, 0, dbf, v);
+#else // !NEW_WAY
+ if (add_field(&sql, cnm, typ, prec, dec, tm, rem, dft, xtra,
+ 0, dbf, v))
+ rc= HA_ERR_OUT_OF_MEM;
+#endif // !NEW_WAY
+ } // endfor i
+
+#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);
+// rc= init_table_share(thd, table_s, create_info, dsn, &sql);
+#endif // !NEW_WAY
+
+ return rc;
+ } // endif ok
+
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ return HA_ERR_INTERNAL_ERROR;
+} // end of connect_assisted_discovery
+
+/**
+ Get the database name from a qualified table name.
+*/
+char *ha_connect::GetDBfromName(const char *name)
+{
+ char *db, dbname[128], tbname[128];
+
+ if (filename_to_dbname_and_tablename(name, dbname, sizeof(dbname),
+ tbname, sizeof(tbname)))
+ *dbname= 0;
+
+ if (*dbname) {
+ assert(xp && xp->g);
+ db= (char*)PlugSubAlloc(xp->g, NULL, strlen(dbname + 1));
+ strcpy(db, dbname);
+ } else
+ db= NULL;
+
+ return db;
+} // end of GetDBfromName
+
+
+/**
+ @brief
+ create() is called to create a database. The variable name will have the name
+ of the table.
+
+ @details
+ When create() is called you do not need to worry about
+ opening the table. Also, the .frm file will have already been
+ created so adjusting create_info is not necessary. You can overwrite
+ the .frm file at this point if you wish to change the table
+ definition, but there are no methods currently provided for doing
+ so.
+
+ Called from handle.cc by ha_create_table().
+
+ @note
+ Currently we do some checking on the create definitions and stop
+ creating if an error is found. We wish we could change the table
+ definition such as providing a default table type. However, as said
+ above, there are no method to do so.
+
+ @see
+ ha_create_table() in handle.cc
+*/
+
+int ha_connect::create(const char *name, TABLE *table_arg,
+ HA_CREATE_INFO *create_info)
+{
+ int rc= RC_OK;
+ bool dbf;
+ Field* *field;
+ Field *fp;
+ TABTYPE type;
+ TABLE *st= table; // Probably unuseful
+ THD *thd= ha_thd();
+ xp= GetUser(thd, xp);
+ 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)
+ htrc("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);
+
+ // Check table type
+ if (type == TAB_UNDEF) {
+ options->type= (options->srcdef) ? "MYSQL" :
+ (options->tabname) ? "PROXY" : "DOS";
+ type= GetTypeID(options->type);
+ sprintf(g->Message, "No table_type. Will be set to %s", options->type);
+
+ if (sqlcom == SQLCOM_CREATE_TABLE)
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
+
+ } else if (type == TAB_NIY) {
+ sprintf(g->Message, "Unsupported table type %s", options->type);
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+ } // endif ttp
+
+ if (check_privileges(thd, options, GetDBfromName(name)))
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+
+ if (options->data_charset) {
+ const CHARSET_INFO *data_charset;
+
+ if (!(data_charset= get_charset_by_csname(options->data_charset,
+ MY_CS_PRIMARY, MYF(0)))) {
+ my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), options->data_charset);
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+ } // endif charset
+
+ if (type == TAB_XML && data_charset != &my_charset_utf8_general_ci) {
+ my_printf_error(ER_UNKNOWN_ERROR,
+ "DATA_CHARSET='%s' is not supported for TABLE_TYPE=XML",
+ MYF(0), options->data_charset);
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+ } // endif utf8
+
+ } // endif charset
+
+ if (!g) {
+ rc= HA_ERR_INTERNAL_ERROR;
+ DBUG_RETURN(rc);
+ } else
+ dbf= (GetTypeID(options->type) == TAB_DBF && !options->catfunc);
+
+ // Can be null in ALTER TABLE
+ if (create_info->alias)
+ // Check whether a table is defined on itself
+ switch (type) {
+ case TAB_PRX:
+ case TAB_XCL:
+ case TAB_PIVOT:
+ case TAB_OCCUR:
+ if (options->srcdef) {
+ strcpy(g->Message, "Cannot check looping reference");
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
+ } else if (options->tabname) {
+ if (!stricmp(options->tabname, create_info->alias) &&
+ (!options->dbname || !stricmp(options->dbname, table_arg->s->db.str))) {
+ sprintf(g->Message, "A %s table cannot refer to itself",
+ options->type);
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+ } // endif tab
+
+ } else {
+ strcpy(g->Message, "Missing object table name or definition");
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+ } // endif tabname
+
+ case TAB_MYSQL:
+ {const char *src= options->srcdef;
+ char *host, *db, *tab= (char*)options->tabname;
+ int port;
+
+ host= GetListOption(g, "host", options->oplist, NULL);
+ db= GetListOption(g, "database", options->oplist, NULL);
+ port= atoi(GetListOption(g, "port", options->oplist, "0"));
+
+ if (create_info->connect_string.str) {
+ char *dsn;
+ int len= create_info->connect_string.length;
+ PMYDEF mydef= new(g) MYSQLDEF();
+ PDBUSER dup= PlgGetUser(g);
+ PCATLG cat= (dup) ? dup->Catalog : NULL;
+
+ dsn= (char*)PlugSubAlloc(g, NULL, len + 1);
+ strncpy(dsn, create_info->connect_string.str, len);
+ dsn[len]= 0;
+ mydef->SetName(create_info->alias);
+ mydef->SetCat(cat);
+
+ if (!mydef->ParseURL(g, dsn, false)) {
+ if (mydef->GetHostname())
+ host= mydef->GetHostname();
+
+ if (mydef->GetDatabase())
+ db= mydef->GetDatabase();
+
+ if (mydef->GetTabname())
+ tab= mydef->GetTabname();
+
+ if (mydef->GetPortnumber())
+ port= mydef->GetPortnumber();
+
+ } else {
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+ } // endif ParseURL
+
+ } // endif connect_string
+
+ if (CheckSelf(g, table_arg->s, host, db, tab, src, port)) {
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+ } // endif CheckSelf
+
+ }break;
+ default: /* do nothing */;
+ break;
+ } // endswitch ttp
+
+ if (type == TAB_XML) {
+ bool dom; // True: MS-DOM, False libxml2
+ char *xsup= GetListOption(g, "Xmlsup", options->oplist, "*");
+
+ // Note that if no support is specified, the default is MS-DOM
+ // on Windows and libxml2 otherwise
+ switch (*xsup) {
+ case '*':
+#if defined(WIN32)
+ dom= true;
+#else // !WIN32
+ dom= false;
+#endif // !WIN32
+ break;
+ case 'M':
+ case 'D':
+ dom= true;
+ break;
+ default:
+ dom= false;
+ break;
+ } // endswitch xsup
+
+#if !defined(DOMDOC_SUPPORT)
+ if (dom) {
+ strcpy(g->Message, "MS-DOM not supported by this version");
+ xsup= NULL;
+ } // endif DomDoc
+#endif // !DOMDOC_SUPPORT
+
+#if !defined(LIBXML2_SUPPORT)
+ if (!dom) {
+ strcpy(g->Message, "libxml2 not supported by this version");
+ xsup= NULL;
+ } // endif Libxml2
+#endif // !LIBXML2_SUPPORT
+
+ if (!xsup) {
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ rc= HA_ERR_INTERNAL_ERROR;
+ DBUG_RETURN(rc);
+ } // endif xsup
+
+ } // endif type
+
+ // Check column types
+ for (field= table_arg->field; *field; field++) {
+ fp= *field;
+
+ if (fp->vcol_info && !fp->stored_in_db)
+ continue; // This is a virtual column
+
+ if (fp->flags & AUTO_INCREMENT_FLAG) {
+ strcpy(g->Message, "Auto_increment is not supported yet");
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ rc= HA_ERR_INTERNAL_ERROR;
+ DBUG_RETURN(rc);
+ } // endif flags
+
+ if (fp->flags & (BLOB_FLAG | ENUM_FLAG | SET_FLAG)) {
+ sprintf(g->Message, "Unsupported type for column %s",
+ fp->field_name);
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ rc= HA_ERR_INTERNAL_ERROR;
+ DBUG_RETURN(rc);
+ } // endif flags
+
+ switch (fp->type()) {
+ case MYSQL_TYPE_SHORT:
+ case MYSQL_TYPE_LONG:
+ case MYSQL_TYPE_FLOAT:
+ case MYSQL_TYPE_DOUBLE:
+ case MYSQL_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_DATE:
+ case MYSQL_TYPE_TIME:
+ case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_YEAR:
+ case MYSQL_TYPE_NEWDATE:
+ case MYSQL_TYPE_LONGLONG:
+ case MYSQL_TYPE_TINY:
+ case MYSQL_TYPE_DECIMAL:
+ case MYSQL_TYPE_NEWDECIMAL:
+ case MYSQL_TYPE_INT24:
+ break; // Ok
+ case MYSQL_TYPE_VARCHAR:
+ case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_STRING:
+ if (!fp->field_length) {
+ sprintf(g->Message, "Unsupported 0 length for column %s",
+ fp->field_name);
+ rc= HA_ERR_INTERNAL_ERROR;
+ my_printf_error(ER_UNKNOWN_ERROR,
+ "Unsupported 0 length for column %s",
+ MYF(0), fp->field_name);
+ DBUG_RETURN(rc);
+ } // endif fp
+
+ break; // To be checked
+ case MYSQL_TYPE_BIT:
+ case MYSQL_TYPE_NULL:
+ case MYSQL_TYPE_ENUM:
+ case MYSQL_TYPE_SET:
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_GEOMETRY:
+ default:
+// fprintf(stderr, "Unsupported type column %s\n", fp->field_name);
+ sprintf(g->Message, "Unsupported type for column %s",
+ fp->field_name);
+ rc= HA_ERR_INTERNAL_ERROR;
+ my_printf_error(ER_UNKNOWN_ERROR, "Unsupported type for column %s",
+ MYF(0), fp->field_name);
+ DBUG_RETURN(rc);
+ break;
+ } // endswitch type
+
+ if ((fp)->real_maybe_null() && !IsTypeNullable(type)) {
+ my_printf_error(ER_UNKNOWN_ERROR,
+ "Table type %s does not support nullable columns",
+ MYF(0), options->type);
+ DBUG_RETURN(HA_ERR_UNSUPPORTED);
+ } // endif !nullable
+
+ if (dbf) {
+ bool b= false;
+
+ if ((b= strlen(fp->field_name) > 10))
+ sprintf(g->Message, "DBF: Column name '%s' is too long (max=10)",
+ fp->field_name);
+ else if ((b= fp->field_length > 255))
+ sprintf(g->Message, "DBF: Column length too big for '%s' (max=255)",
+ fp->field_name);
+
+ if (b) {
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ rc= HA_ERR_INTERNAL_ERROR;
+ DBUG_RETURN(rc);
+ } // endif b
+
+ } // endif dbf
+
+ } // endfor field
+
+ 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]);
+
+ strcat(strcat(buf, "."), lwt);
+ sprintf(g->Message, "No file name. Table will use %s", buf);
+
+ if (sqlcom == SQLCOM_CREATE_TABLE)
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
+
+ strcat(strcat(strcpy(dbpath, "./"), table->s->db.str), "/");
+ PlugSetPath(fn, buf, dbpath);
+
+ 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(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
+ } else
+ ::close(h);
+
+ if (type == TAB_FMT || options->readonly)
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0,
+ "Congratulation, you just created a read-only void table!");
+
+ } // endif
+
+ if (xtrace)
+ htrc("xchk=%p createas=%d\n", g->Xchk, g->Createas);
+
+ // To check whether indices have to be made or remade
+ if (!g->Xchk) {
+ PIXDEF xdp;
+
+ // 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)) {
+ PDBUSER dup= PlgGetUser(g);
+ PCATLG cat= (dup) ? dup->Catalog : NULL;
+
+ if (cat) {
+ cat->SetDataPath(g, table_arg->s->db.str);
+
+ if ((rc= optimize(table->in_use, NULL))) {
+ htrc("Create rc=%d %s\n", rc, g->Message);
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ rc= HA_ERR_INTERNAL_ERROR;
+ } else
+ CloseTable(g);
+
+ } // endif cat
+
+ } else {
+ sprintf(g->Message, "Table type %s is not indexable", options->type);
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ rc= HA_ERR_UNSUPPORTED;
+ } // endif Indexable
+
+ } // 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)) {
+ g->Xchk= NULL;
+ sprintf(g->Message, "Table type %s is not indexable", options->type);
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ rc= HA_ERR_INTERNAL_ERROR;
+ } else {
+ xcp->newpix= xdp;
+ xcp->newsep= GetBooleanOption("Sepindex", false);
+ } // endif Indexable
+
+ } else if (!xcp->oldpix)
+ g->Xchk= NULL;
+
+ if (xtrace && g->Xchk)
+ htrc("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
+
+// Called by SameString and NoFieldOptionChange
+bool ha_connect::CheckString(const char *str1, const char *str2)
+{
+ bool 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 CheckString
+
+/**
+ check whether a string option have changed
+ */
+bool ha_connect::SameString(TABLE *tab, char *opn)
+{
+ char *str1, *str2;
+
+ tshp= tab->s; // The altered table
+ str1= GetStringOption(opn);
+ tshp= NULL;
+ str2= GetStringOption(opn);
+ return CheckString(str1, str2);
+} // end of SameString
+
+/**
+ 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 whether a field option have changed
+ */
+bool ha_connect::NoFieldOptionChange(TABLE *tab)
+{
+ bool rc= true;
+ ha_field_option_struct *fop1, *fop2;
+ Field* *fld1= table->s->field;
+ Field* *fld2= tab->s->field;
+
+ for (; rc && *fld1 && *fld2; fld1++, fld2++) {
+ fop1= (*fld1)->option_struct;
+ fop2= (*fld2)->option_struct;
+
+ rc= (fop1->offset == fop2->offset &&
+ fop1->fldlen == fop2->fldlen &&
+ CheckString(fop1->dateformat, fop2->dateformat) &&
+ CheckString(fop1->fieldformat, fop2->fieldformat) &&
+ CheckString(fop1->special, fop2->special));
+ } // endfor fld
+
+ return rc;
+} // end of NoFieldOptionChange
+
+ /**
+ 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 ||
+ !SameString(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)
+ htrc(
+ "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 (!SameString(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 (NoFieldOptionChange(altered_table) &&
+ 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_ALTER_OPERATION_NOT_SUPPORTED,
+ "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
+ if new and old definition are compatible
+
+ @details If there are no other explicit signs like changed number of
+ fields this function will be called by compare_tables()
+ (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)
+{
+ DBUG_ENTER("ha_connect::check_if_incompatible_data");
+ // TO DO: really implement and check it.
+ 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
+
+/****************************************************************************
+ * CONNECT MRR implementation: use DS-MRR
+ This is just copied from myisam
+ ***************************************************************************/
+
+int ha_connect::multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param,
+ uint n_ranges, uint mode,
+ HANDLER_BUFFER *buf)
+{
+ return ds_mrr.dsmrr_init(this, seq, seq_init_param, n_ranges, mode, buf);
+} // end of multi_range_read_init
+
+int ha_connect::multi_range_read_next(range_id_t *range_info)
+{
+ return ds_mrr.dsmrr_next(range_info);
+} // end of multi_range_read_next
+
+ha_rows ha_connect::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
+ void *seq_init_param,
+ uint n_ranges, uint *bufsz,
+ uint *flags, Cost_estimate *cost)
+{
+ /*
+ This call is here because there is no location where this->table would
+ already be known.
+ TODO: consider moving it into some per-query initialization call.
+ */
+ ds_mrr.init(this, table);
+
+ // MMR is implemented for "local" file based tables only
+ if (!IsFileType(GetRealType(GetTableOptionStruct(table))))
+ *flags|= HA_MRR_USE_DEFAULT_IMPL;
+
+ ha_rows rows= ds_mrr.dsmrr_info_const(keyno, seq, seq_init_param, n_ranges,
+ bufsz, flags, cost);
+ xp->g->Mrr= !(*flags & HA_MRR_USE_DEFAULT_IMPL);
+ return rows;
+} // end of multi_range_read_info_const
+
+ha_rows ha_connect::multi_range_read_info(uint keyno, uint n_ranges, uint keys,
+ uint key_parts, uint *bufsz,
+ uint *flags, Cost_estimate *cost)
+{
+ ds_mrr.init(this, table);
+
+ // MMR is implemented for "local" file based tables only
+ if (!IsFileType(GetRealType(GetTableOptionStruct(table))))
+ *flags|= HA_MRR_USE_DEFAULT_IMPL;
+
+ ha_rows rows= ds_mrr.dsmrr_info(keyno, n_ranges, keys, key_parts, bufsz,
+ flags, cost);
+ xp->g->Mrr= !(*flags & HA_MRR_USE_DEFAULT_IMPL);
+ return rows;
+} // end of multi_range_read_info
+
+
+int ha_connect::multi_range_read_explain_info(uint mrr_mode, char *str,
+ size_t size)
+{
+ return ds_mrr.dsmrr_explain_info(mrr_mode, str, size);
+} // end of multi_range_read_explain_info
+
+/* CONNECT MRR implementation ends */
+
+#if 0
+// Does this make sens for CONNECT?
+Item *ha_connect::idx_cond_push(uint keyno_arg, Item* idx_cond_arg)
+{
+ pushed_idx_cond_keyno= keyno_arg;
+ pushed_idx_cond= idx_cond_arg;
+ in_range_check_pushed_down= TRUE;
+ if (active_index == pushed_idx_cond_keyno)
+ mi_set_index_cond_func(file, handler_index_cond_check, this);
+ return NULL;
+}
+#endif // 0
+
+
+struct st_mysql_storage_engine connect_storage_engine=
+{ MYSQL_HANDLERTON_INTERFACE_VERSION };
+
+// Tracing: 0 no, 1 yes, >1 more tracing
+static MYSQL_SYSVAR_INT(xtrace, xtrace,
+ PLUGIN_VAR_RQCMDARG, "Console trace value.",
+ NULL, update_connect_xtrace, 0, 0, INT_MAX, 1);
+
+// Size used when converting TEXT columns to VARCHAR
+static MYSQL_SYSVAR_INT(conv_size, conv_size,
+ PLUGIN_VAR_RQCMDARG, "Size used when converting TEXT columns.",
+ NULL, update_connect_zconv, SZCONV, 0, 65500, 1);
+
+/**
+ Type conversion:
+ no: Unsupported types -> TYPE_ERROR
+ yes: TEXT -> VARCHAR
+ skip: skip unsupported type columns in Discovery
+*/
+const char *xconv_names[]=
+{
+ "NO", "YES", "SKIP", NullS
+};
+
+TYPELIB xconv_typelib=
+{
+ array_elements(xconv_names) - 1, "xconv_typelib",
+ xconv_names, NULL
+};
+
+static MYSQL_SYSVAR_ENUM(
+ type_conv, // name
+ type_conv, // varname
+ PLUGIN_VAR_RQCMDARG, // opt
+ "Unsupported types conversion.", // comment
+ NULL, // check
+ update_connect_xconv, // update function
+ 0, // def (no)
+ &xconv_typelib); // typelib
+
+#if defined(XMAP)
+// Using file mapping for indexes if true
+static MYSQL_SYSVAR_BOOL(indx_map, indx_map, PLUGIN_VAR_RQCMDARG,
+ "Using file mapping for indexes",
+ NULL, update_connect_xmap, 0);
+#endif // XMAP
+
+// Size used for g->Sarea_Size
+static MYSQL_SYSVAR_UINT(work_size, work_size,
+ PLUGIN_VAR_RQCMDARG, "Size of the CONNECT work area.",
+ NULL, update_connect_worksize, SZWORK, SZWMIN, UINT_MAX, 1);
+
+static struct st_mysql_sys_var* connect_system_variables[]= {
+ MYSQL_SYSVAR(xtrace),
+ MYSQL_SYSVAR(conv_size),
+ MYSQL_SYSVAR(type_conv),
+#if defined(XMAP)
+ MYSQL_SYSVAR(indx_map),
+#endif // XMAP
+ MYSQL_SYSVAR(work_size),
+ NULL
+};
+
+maria_declare_plugin(connect)
+{
+ MYSQL_STORAGE_ENGINE_PLUGIN,
+ &connect_storage_engine,
+ "CONNECT",
+ "Olivier Bertrand",
+ "Management of External Data (SQL/MED), including many file formats",
+ PLUGIN_LICENSE_GPL,
+ connect_init_func, /* Plugin Init */
+ connect_done_func, /* Plugin Deinit */
+ 0x0103, /* version number (1.03) */
+ NULL, /* status variables */
+ connect_system_variables, /* system variables */
+ "1.03", /* string version */
+ MariaDB_PLUGIN_MATURITY_BETA /* maturity */
+}
+maria_declare_plugin_end;
diff --git a/storage/connect/ha_connect.h b/storage/connect/ha_connect.h
index d8395335edb..46763394945 100644
--- a/storage/connect/ha_connect.h
+++ b/storage/connect/ha_connect.h
@@ -1,135 +1,135 @@
-/* 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
- the Free Software Foundation; version 2 of the License.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/** @file ha_connect.h
-
- @brief
- The ha_connect engine is a prototype storage engine to access external data.
-
- @see
- /sql/handler.h and /storage/connect/ha_connect.cc
-*/
-
-#ifdef USE_PRAGMA_INTERFACE
-#pragma interface /* gcc class implementation */
-#endif
-
-/****************************************************************************/
-/* Structures used to pass info between CONNECT and ha_connect. */
-/****************************************************************************/
-typedef struct _create_xinfo {
- char *Type; /* Retrieved from table comment */
- char *Filename; /* Set if not standard */
- char *IndexFN; /* Set if not standard */
- ulonglong Maxrows; /* Estimated max nb of rows */
- ulong Lrecl; /* Set if not default */
- ulong Elements; /* Number of lines in blocks */
- bool Fixed; /* False for DOS type */
- void *Pcf; /* To list of columns */
- void *Pxdf; /* To list of indexes */
-} CRXINFO, *PCXF;
-
-typedef struct _xinfo {
- ulonglong data_file_length; /* Length of data file */
- ha_rows records; /* Records in table */
- ulong mean_rec_length; /* Physical record length */
- char *data_file_name; /* Physical file name */
-} XINFO, *PXF;
-
-class XCHK : public BLOCK {
-public:
- 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
-
-typedef class XCHK *PCHK;
-typedef class user_connect *PCONNECT;
-typedef struct ha_table_option_struct TOS, *PTOS;
-typedef struct ha_field_option_struct FOS, *PFOS;
-
-extern handlerton *connect_hton;
-
-/**
- structure for CREATE TABLE options (table options)
-
- These can be specified in the CREATE TABLE:
- CREATE TABLE ( ... ) {...here...}
-*/
-struct ha_table_option_struct {
- const char *type;
- const char *filename;
- const char *optname;
- const char *tabname;
- const char *tablist;
- const char *dbname;
- const char *separator;
-//const char *connect;
- const char *qchar;
- const char *module;
- const char *subtype;
- const char *catfunc;
- const char *srcdef;
- const char *colist;
- const char *oplist;
- const char *data_charset;
- ulonglong lrecl;
- ulonglong elements;
-//ulonglong estimate;
- ulonglong multiple;
- ulonglong header;
- ulonglong quoted;
- ulonglong ending;
- ulonglong compressed;
- bool mapped;
- bool huge;
- bool split;
- bool readonly;
- bool sepindex;
- };
-
-/**
- structure for CREATE TABLE options (field options)
-
- These can be specified in the CREATE TABLE per field:
- CREATE TABLE ( field ... {...here...}, ... )
-*/
-struct ha_field_option_struct
-{
- ulonglong offset;
- ulonglong freq;
- ulonglong opt;
- ulonglong fldlen;
- const char *dateformat;
- const char *fieldformat;
- char *special;
-};
-
+/* 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
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/** @file ha_connect.h
+
+ @brief
+ The ha_connect engine is a prototype storage engine to access external data.
+
+ @see
+ /sql/handler.h and /storage/connect/ha_connect.cc
+*/
+
+#ifdef USE_PRAGMA_INTERFACE
+#pragma interface /* gcc class implementation */
+#endif
+
+/****************************************************************************/
+/* Structures used to pass info between CONNECT and ha_connect. */
+/****************************************************************************/
+typedef struct _create_xinfo {
+ char *Type; /* Retrieved from table comment */
+ char *Filename; /* Set if not standard */
+ char *IndexFN; /* Set if not standard */
+ ulonglong Maxrows; /* Estimated max nb of rows */
+ ulong Lrecl; /* Set if not default */
+ ulong Elements; /* Number of lines in blocks */
+ bool Fixed; /* False for DOS type */
+ void *Pcf; /* To list of columns */
+ void *Pxdf; /* To list of indexes */
+} CRXINFO, *PCXF;
+
+typedef struct _xinfo {
+ ulonglong data_file_length; /* Length of data file */
+ ha_rows records; /* Records in table */
+ ulong mean_rec_length; /* Physical record length */
+ char *data_file_name; /* Physical file name */
+} XINFO, *PXF;
+
+class XCHK : public BLOCK {
+public:
+ 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
+
+typedef class XCHK *PCHK;
+typedef class user_connect *PCONNECT;
+typedef struct ha_table_option_struct TOS, *PTOS;
+typedef struct ha_field_option_struct FOS, *PFOS;
+
+extern handlerton *connect_hton;
+
+/**
+ structure for CREATE TABLE options (table options)
+
+ These can be specified in the CREATE TABLE:
+ CREATE TABLE ( ... ) {...here...}
+*/
+struct ha_table_option_struct {
+ const char *type;
+ const char *filename;
+ const char *optname;
+ const char *tabname;
+ const char *tablist;
+ const char *dbname;
+ const char *separator;
+//const char *connect;
+ const char *qchar;
+ const char *module;
+ const char *subtype;
+ const char *catfunc;
+ const char *srcdef;
+ const char *colist;
+ const char *oplist;
+ const char *data_charset;
+ ulonglong lrecl;
+ ulonglong elements;
+//ulonglong estimate;
+ ulonglong multiple;
+ ulonglong header;
+ ulonglong quoted;
+ ulonglong ending;
+ ulonglong compressed;
+ bool mapped;
+ bool huge;
+ bool split;
+ bool readonly;
+ bool sepindex;
+ };
+
+/**
+ structure for CREATE TABLE options (field options)
+
+ These can be specified in the CREATE TABLE per field:
+ CREATE TABLE ( field ... {...here...}, ... )
+*/
+struct ha_field_option_struct
+{
+ ulonglong offset;
+ ulonglong freq;
+ ulonglong opt;
+ ulonglong fldlen;
+ const char *dateformat;
+ const char *fieldformat;
+ char *special;
+};
+
/*
index options can be declared similarly
using the ha_index_option_struct structure.
@@ -137,401 +137,402 @@ struct ha_field_option_struct
Their values can be specified in the CREATE TABLE per index:
CREATE TABLE ( field ..., .., INDEX .... *here*, ... )
*/
-struct ha_index_option_struct
-{
- bool kindx;
- bool mapped;
-};
-
-/** @brief
- CONNECT_SHARE is a structure that will be shared among all open handlers.
- This example implements the minimum of what you will probably need.
-*/
-class CONNECT_SHARE : public Handler_share {
-public:
- mysql_mutex_t mutex;
- THR_LOCK lock;
- CONNECT_SHARE()
- {
- thr_lock_init(&lock);
- }
- ~CONNECT_SHARE()
- {
- thr_lock_delete(&lock);
- mysql_mutex_destroy(&mutex);
- }
-};
-
-typedef class ha_connect *PHC;
-
-/** @brief
- Class definition for the storage engine
-*/
-class ha_connect: public handler
-{
- THR_LOCK_DATA lock; ///< MySQL lock
- CONNECT_SHARE *share; ///< Shared lock info
- CONNECT_SHARE *get_share();
-
-public:
- ha_connect(handlerton *hton, TABLE_SHARE *table_arg);
- ~ha_connect();
-
- // 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 CheckString(const char *str1, const char *str2);
- bool SameString(TABLE *tab, char *opn);
- bool SetIntegerOption(char *opname, int n);
- bool SameInt(TABLE *tab, char *opn);
- bool SameBool(TABLE *tab, char *opn);
- bool FileExists(const char *fn);
- bool NoFieldOptionChange(TABLE *tab);
- PFOS GetFieldOptionStruct(Field *fp);
- void *GetColumnOption(PGLOBAL g, void *field, PCOLINFO pcf);
- PIXDEF GetIndexInfo(TABLE_SHARE *s= NULL);
- const char *GetDBName(const char *name);
- const char *GetTableName(void);
-//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);
-
- PTDB GetTDB(PGLOBAL g);
- int OpenTable(PGLOBAL g, bool del= false);
- bool IsOpened(void);
- int CloseTable(PGLOBAL g);
- int MakeRecord(char *buf);
- int ScanRecord(PGLOBAL g, uchar *buf);
- int CheckRecord(PGLOBAL g, const uchar *oldbuf, uchar *newbuf);
- int ReadIndexed(uchar *buf, OPVAL op, const uchar* key= NULL,
- uint key_len= 0);
-
- /** @brief
- The name that will be used for display purposes.
- */
- const char *table_type() const {return "CONNECT";}
-
- /** @brief
- The name of the index type that will be used for display.
- Don't implement this method unless you really have indexes.
- */
- const char *index_type(uint inx) { return "XINDEX"; }
-
- /** @brief
- The file extensions.
- */
- 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;
-
- /** @brief
- This is a bitmap of flags that indicates how the storage engine
- implements indexes. The current index flags are documented in
- handler.h. If you do not implement indexes, just return zero here.
-
- @details
- part is the key part to check. First key part is 0.
- If all_parts is set, MySQL wants to know the flags for the combined
- index, up to and including 'part'.
- */
- ulong index_flags(uint inx, uint part, bool all_parts) const
- {
- return HA_READ_NEXT | HA_READ_RANGE | HA_READ_ORDER | HA_KEYREAD_ONLY;
- } // end of index_flags
-
- /** @brief
- unireg.cc will call max_supported_record_length(), max_supported_keys(),
- max_supported_key_parts(), uint max_supported_key_length()
- to make sure that the storage engine can handle the data it is about to
- send. Return *real* limits of your storage engine here; MySQL will do
- min(your_limits, MySQL_limits) automatically.
- */
- uint max_supported_record_length() const { return HA_MAX_REC_LENGTH; }
-
- /** @brief
- unireg.cc will call this to make sure that the storage engine can handle
- the data it is about to send. Return *real* limits of your storage engine
- here; MySQL will do min(your_limits, MySQL_limits) automatically.
-
- @details
- There is no need to implement ..._key_... methods if your engine doesn't
- support indexes.
- */
- uint max_supported_keys() const { return 10; }
-
- /** @brief
- unireg.cc will call this to make sure that the storage engine can handle
- the data it is about to send. Return *real* limits of your storage engine
- here; MySQL will do min(your_limits, MySQL_limits) automatically.
-
- @details
- There is no need to implement ..._key_... methods if your engine doesn't
- support indexes.
- */
- uint max_supported_key_parts() const { return 10; }
-
- /** @brief
- unireg.cc will call this to make sure that the storage engine can handle
- the data it is about to send. Return *real* limits of your storage engine
- here; MySQL will do min(your_limits, MySQL_limits) automatically.
-
- @details
- There is no need to implement ..._key_... methods if your engine doesn't
- support indexes.
- */
- uint max_supported_key_length() const { return 255; }
-
- /** @brief
- Called in test_quick_select to determine if indexes should be used.
- */
- virtual double scan_time() { return (double) (stats.records+stats.deleted) / 20.0+10; }
-
- /** @brief
- This method will never be called if you do not implement indexes.
- */
- virtual double read_time(uint, uint, ha_rows rows)
- { return (double) rows / 20.0+1; }
-
- /*
- Everything below are methods that we implement in ha_connect.cc.
-
- Most of these methods are not obligatory, skip them and
- MySQL will treat them as not implemented
- */
- virtual bool get_error_message(int error, String *buf);
-
- /**
- Push condition down to the table handler.
-
- @param cond Condition to be pushed. The condition tree must not be
- modified by the by the caller.
-
- @return
- The 'remainder' condition that caller must use to filter out records.
- NULL means the handler will not return rows that do not match the
- passed condition.
-
- @note
- The pushed conditions form a stack (from which one can remove the
- last pushed condition using cond_pop).
- The table handler filters out rows using (pushed_cond1 AND pushed_cond2
- AND ... AND pushed_condN)
- or less restrictive condition, depending on handler's capabilities.
-
- handler->ha_reset() call empties the condition stack.
- Calls to rnd_init/rnd_end, index_init/index_end etc do not affect the
- condition stack.
- */
-virtual const COND *cond_push(const COND *cond);
-PCFIL CheckCond(PGLOBAL g, PCFIL filp, AMT tty, Item *cond);
-const char *GetValStr(OPVAL vop, bool neg);
-PFIL CondFilter(PGLOBAL g, Item *cond);
-
- /**
- Number of rows in table. It will only be called if
- (table_flags() & (HA_HAS_RECORDS | HA_STATS_RECORDS_IS_EXACT)) != 0
- */
- 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.
- */
- int open(const char *name, int mode, uint test_if_locked); // required
-
- /** @brief
- We implement this in ha_connect.cc; it's a required method.
- */
- int close(void); // required
-
- /** @brief
- We implement this in ha_connect.cc. It's not an obligatory method;
- skip it and and MySQL will treat it as not implemented.
- */
- int write_row(uchar *buf);
-
- /** @brief
- We implement this in ha_connect.cc. It's not an obligatory method;
- skip it and and MySQL will treat it as not implemented.
- */
- int update_row(const uchar *old_data, uchar *new_data);
-
- /** @brief
- We implement this in ha_connect.cc. It's not an obligatory method;
- skip it and and MySQL will treat it as not implemented.
- */
- int delete_row(const uchar *buf);
-
- // Added to the connect handler
- int index_init(uint idx, bool sorted);
- int index_end();
- int index_read(uchar * buf, const uchar * key, uint key_len,
- enum ha_rkey_function find_flag);
- int index_next_same(uchar *buf, const uchar *key, uint keylen);
-
- /** @brief
- We implement this in ha_connect.cc. It's not an obligatory method;
- skip it and and MySQL will treat it as not implemented.
- */
-//int index_read_map(uchar *buf, const uchar *key,
-// key_part_map keypart_map, enum ha_rkey_function find_flag);
-
- /** @brief
- We implement this in ha_connect.cc. It's not an obligatory method;
- skip it and and MySQL will treat it as not implemented.
- */
- int index_next(uchar *buf);
-
- /** @brief
- We implement this in ha_connect.cc. It's not an obligatory method;
- skip it and and MySQL will treat it as not implemented.
- */
-//int index_prev(uchar *buf);
-
- /** @brief
- We implement this in ha_connect.cc. It's not an obligatory method;
- skip it and and MySQL will treat it as not implemented.
- */
- int index_first(uchar *buf);
-
- /** @brief
- We implement this in ha_connect.cc. It's not an obligatory method;
- skip it and and MySQL will treat it as not implemented.
- */
-//int index_last(uchar *buf);
-
- /* Index condition pushdown implementation */
-//Item *idx_cond_push(uint keyno, Item* idx_cond);
-
- /** @brief
- Unlike index_init(), rnd_init() can be called two consecutive times
- without rnd_end() in between (it only makes sense if scan=1). In this
- case, the second call should prepare for the new table scan (e.g if
- rnd_init() allocates the cursor, the second call should position the
- cursor to the start of the table; no need to deallocate and allocate
- it again. This is a required method.
- */
- int rnd_init(bool scan); //required
- int rnd_end();
- int rnd_next(uchar *buf); ///< required
- int rnd_pos(uchar *buf, uchar *pos); ///< required
- 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,
- key_range *max_key);
- /**
- These methods can be overridden, but their default implementation
- provide useful functionality.
- */
- int rename_table(const char *from, const char *to);
- /**
- Delete a table in the engine. Called for base as well as temporary
- tables.
- */
- int delete_table(const char *name);
- /**
- Called by delete_table and rename_table
- */
- int delete_or_rename_table(const char *from, const char *to);
- int create(const char *name, TABLE *form,
- HA_CREATE_INFO *create_info); ///< required
- bool check_if_incompatible_data(HA_CREATE_INFO *info,
- uint table_changes);
-
- THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
- enum thr_lock_type lock_type); ///< required
- int optimize(THD* thd, HA_CHECK_OPT* check_opt);
-
- /**
- * Multi Range Read interface
- */
- int multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param,
- uint n_ranges, uint mode, HANDLER_BUFFER *buf);
- int multi_range_read_next(range_id_t *range_info);
- ha_rows multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
- void *seq_init_param,
- uint n_ranges, uint *bufsz,
- uint *flags, Cost_estimate *cost);
- ha_rows multi_range_read_info(uint keyno, uint n_ranges, uint keys,
- uint key_parts, uint *bufsz,
- uint *flags, Cost_estimate *cost);
- int multi_range_read_explain_info(uint mrr_mode, char *str, size_t size);
-
- int reset(void) {ds_mrr.dsmrr_close(); return 0;}
-
- /* Index condition pushdown implementation */
-// Item *idx_cond_push(uint keyno, Item* idx_cond);
-private:
- DsMrr_impl ds_mrr;
-
-protected:
- bool check_privileges(THD *thd, PTOS options, char *dbn);
- MODE CheckMode(PGLOBAL g, THD *thd, MODE newmode, bool *chk, bool *cras);
- char *GetDBfromName(const char *name);
-
- // Members
- static ulong num; // Tracable handler number
- PCONNECT xp; // To user_connect associated class
- ulong hnum; // The number of this handler
- query_id_t valid_query_id; // The one when tdbp was allocated
- query_id_t creat_query_id; // The one when handler was allocated
- PTDB tdbp; // To table class object
- PVAL sdvalin; // Used to convert date values
- PVAL sdvalout; // Used to convert date values
- bool istable; // True for table handler
-//char tname[64]; // The table name
- MODE xmod; // Table mode
- 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
- bool mrr; // True when getting index positions
- int indexing; // Type of indexing for CONNECT
- int locked; // Table lock
- THR_LOCK_DATA lock_data;
-
-public:
- TABLE_SHARE *tshp; // Used by called tables
- char *data_file_name;
- char *index_file_name;
- uint int_table_flags; // Inherited from MyISAM
- bool enable_activate_all_index; // Inherited from MyISAM
-}; // end of ha_connect class definition
+struct ha_index_option_struct
+{
+ bool kindx;
+ bool mapped;
+};
+
+/** @brief
+ CONNECT_SHARE is a structure that will be shared among all open handlers.
+ This example implements the minimum of what you will probably need.
+*/
+class CONNECT_SHARE : public Handler_share {
+public:
+ mysql_mutex_t mutex;
+ THR_LOCK lock;
+ CONNECT_SHARE()
+ {
+ thr_lock_init(&lock);
+ }
+ ~CONNECT_SHARE()
+ {
+ thr_lock_delete(&lock);
+ mysql_mutex_destroy(&mutex);
+ }
+};
+
+typedef class ha_connect *PHC;
+
+/** @brief
+ Class definition for the storage engine
+*/
+class ha_connect: public handler
+{
+ THR_LOCK_DATA lock; ///< MySQL lock
+ CONNECT_SHARE *share; ///< Shared lock info
+ CONNECT_SHARE *get_share();
+
+public:
+ ha_connect(handlerton *hton, TABLE_SHARE *table_arg);
+ ~ha_connect();
+
+ // 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 CheckString(const char *str1, const char *str2);
+ bool SameString(TABLE *tab, char *opn);
+ bool SetIntegerOption(char *opname, int n);
+ bool SameInt(TABLE *tab, char *opn);
+ bool SameBool(TABLE *tab, char *opn);
+ bool FileExists(const char *fn);
+ bool NoFieldOptionChange(TABLE *tab);
+ PFOS GetFieldOptionStruct(Field *fp);
+ void *GetColumnOption(PGLOBAL g, void *field, PCOLINFO pcf);
+ PIXDEF GetIndexInfo(TABLE_SHARE *s= NULL);
+ const char *GetDBName(const char *name);
+ const char *GetTableName(void);
+//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);
+
+ PTDB GetTDB(PGLOBAL g);
+ int OpenTable(PGLOBAL g, bool del= false);
+ bool IsOpened(void);
+ int CloseTable(PGLOBAL g);
+ int MakeRecord(char *buf);
+ int ScanRecord(PGLOBAL g, uchar *buf);
+ int CheckRecord(PGLOBAL g, const uchar *oldbuf, uchar *newbuf);
+ int ReadIndexed(uchar *buf, OPVAL op, const uchar* key= NULL,
+ uint key_len= 0);
+
+ /** @brief
+ The name that will be used for display purposes.
+ */
+ const char *table_type() const {return "CONNECT";}
+
+ /** @brief
+ The name of the index type that will be used for display.
+ Don't implement this method unless you really have indexes.
+ */
+ const char *index_type(uint inx) { return "XINDEX"; }
+
+ /** @brief
+ The file extensions.
+ */
+ 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;
+
+ /** @brief
+ This is a bitmap of flags that indicates how the storage engine
+ implements indexes. The current index flags are documented in
+ handler.h. If you do not implement indexes, just return zero here.
+
+ @details
+ part is the key part to check. First key part is 0.
+ If all_parts is set, MySQL wants to know the flags for the combined
+ index, up to and including 'part'.
+ */
+ ulong index_flags(uint inx, uint part, bool all_parts) const
+ {
+ return HA_READ_NEXT | HA_READ_RANGE | HA_READ_ORDER
+ | HA_KEYREAD_ONLY | HA_KEY_SCAN_NOT_ROR;
+ } // end of index_flags
+
+ /** @brief
+ unireg.cc will call max_supported_record_length(), max_supported_keys(),
+ max_supported_key_parts(), uint max_supported_key_length()
+ to make sure that the storage engine can handle the data it is about to
+ send. Return *real* limits of your storage engine here; MySQL will do
+ min(your_limits, MySQL_limits) automatically.
+ */
+ uint max_supported_record_length() const { return HA_MAX_REC_LENGTH; }
+
+ /** @brief
+ unireg.cc will call this to make sure that the storage engine can handle
+ the data it is about to send. Return *real* limits of your storage engine
+ here; MySQL will do min(your_limits, MySQL_limits) automatically.
+
+ @details
+ There is no need to implement ..._key_... methods if your engine doesn't
+ support indexes.
+ */
+ uint max_supported_keys() const { return 10; }
+
+ /** @brief
+ unireg.cc will call this to make sure that the storage engine can handle
+ the data it is about to send. Return *real* limits of your storage engine
+ here; MySQL will do min(your_limits, MySQL_limits) automatically.
+
+ @details
+ There is no need to implement ..._key_... methods if your engine doesn't
+ support indexes.
+ */
+ uint max_supported_key_parts() const { return 10; }
+
+ /** @brief
+ unireg.cc will call this to make sure that the storage engine can handle
+ the data it is about to send. Return *real* limits of your storage engine
+ here; MySQL will do min(your_limits, MySQL_limits) automatically.
+
+ @details
+ There is no need to implement ..._key_... methods if your engine doesn't
+ support indexes.
+ */
+ uint max_supported_key_length() const { return 255; }
+
+ /** @brief
+ Called in test_quick_select to determine if indexes should be used.
+ */
+ virtual double scan_time() { return (double) (stats.records+stats.deleted) / 20.0+10; }
+
+ /** @brief
+ This method will never be called if you do not implement indexes.
+ */
+ virtual double read_time(uint, uint, ha_rows rows)
+ { return (double) rows / 20.0+1; }
+
+ /*
+ Everything below are methods that we implement in ha_connect.cc.
+
+ Most of these methods are not obligatory, skip them and
+ MySQL will treat them as not implemented
+ */
+ virtual bool get_error_message(int error, String *buf);
+
+ /**
+ Push condition down to the table handler.
+
+ @param cond Condition to be pushed. The condition tree must not be
+ modified by the by the caller.
+
+ @return
+ The 'remainder' condition that caller must use to filter out records.
+ NULL means the handler will not return rows that do not match the
+ passed condition.
+
+ @note
+ The pushed conditions form a stack (from which one can remove the
+ last pushed condition using cond_pop).
+ The table handler filters out rows using (pushed_cond1 AND pushed_cond2
+ AND ... AND pushed_condN)
+ or less restrictive condition, depending on handler's capabilities.
+
+ handler->ha_reset() call empties the condition stack.
+ Calls to rnd_init/rnd_end, index_init/index_end etc do not affect the
+ condition stack.
+ */
+virtual const COND *cond_push(const COND *cond);
+PCFIL CheckCond(PGLOBAL g, PCFIL filp, AMT tty, Item *cond);
+const char *GetValStr(OPVAL vop, bool neg);
+PFIL CondFilter(PGLOBAL g, Item *cond);
+
+ /**
+ Number of rows in table. It will only be called if
+ (table_flags() & (HA_HAS_RECORDS | HA_STATS_RECORDS_IS_EXACT)) != 0
+ */
+ 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.
+ */
+ int open(const char *name, int mode, uint test_if_locked); // required
+
+ /** @brief
+ We implement this in ha_connect.cc; it's a required method.
+ */
+ int close(void); // required
+
+ /** @brief
+ We implement this in ha_connect.cc. It's not an obligatory method;
+ skip it and and MySQL will treat it as not implemented.
+ */
+ int write_row(uchar *buf);
+
+ /** @brief
+ We implement this in ha_connect.cc. It's not an obligatory method;
+ skip it and and MySQL will treat it as not implemented.
+ */
+ int update_row(const uchar *old_data, uchar *new_data);
+
+ /** @brief
+ We implement this in ha_connect.cc. It's not an obligatory method;
+ skip it and and MySQL will treat it as not implemented.
+ */
+ int delete_row(const uchar *buf);
+
+ // Added to the connect handler
+ int index_init(uint idx, bool sorted);
+ int index_end();
+ int index_read(uchar * buf, const uchar * key, uint key_len,
+ enum ha_rkey_function find_flag);
+ int index_next_same(uchar *buf, const uchar *key, uint keylen);
+
+ /** @brief
+ We implement this in ha_connect.cc. It's not an obligatory method;
+ skip it and and MySQL will treat it as not implemented.
+ */
+//int index_read_map(uchar *buf, const uchar *key,
+// key_part_map keypart_map, enum ha_rkey_function find_flag);
+
+ /** @brief
+ We implement this in ha_connect.cc. It's not an obligatory method;
+ skip it and and MySQL will treat it as not implemented.
+ */
+ int index_next(uchar *buf);
+
+ /** @brief
+ We implement this in ha_connect.cc. It's not an obligatory method;
+ skip it and and MySQL will treat it as not implemented.
+ */
+//int index_prev(uchar *buf);
+
+ /** @brief
+ We implement this in ha_connect.cc. It's not an obligatory method;
+ skip it and and MySQL will treat it as not implemented.
+ */
+ int index_first(uchar *buf);
+
+ /** @brief
+ We implement this in ha_connect.cc. It's not an obligatory method;
+ skip it and and MySQL will treat it as not implemented.
+ */
+ int index_last(uchar *buf);
+
+ /* Index condition pushdown implementation */
+//Item *idx_cond_push(uint keyno, Item* idx_cond);
+
+ /** @brief
+ Unlike index_init(), rnd_init() can be called two consecutive times
+ without rnd_end() in between (it only makes sense if scan=1). In this
+ case, the second call should prepare for the new table scan (e.g if
+ rnd_init() allocates the cursor, the second call should position the
+ cursor to the start of the table; no need to deallocate and allocate
+ it again. This is a required method.
+ */
+ int rnd_init(bool scan); //required
+ int rnd_end();
+ int rnd_next(uchar *buf); ///< required
+ int rnd_pos(uchar *buf, uchar *pos); ///< required
+ 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,
+ key_range *max_key);
+ /**
+ These methods can be overridden, but their default implementation
+ provide useful functionality.
+ */
+ int rename_table(const char *from, const char *to);
+ /**
+ Delete a table in the engine. Called for base as well as temporary
+ tables.
+ */
+ int delete_table(const char *name);
+ /**
+ Called by delete_table and rename_table
+ */
+ int delete_or_rename_table(const char *from, const char *to);
+ int create(const char *name, TABLE *form,
+ HA_CREATE_INFO *create_info); ///< required
+ bool check_if_incompatible_data(HA_CREATE_INFO *info,
+ uint table_changes);
+
+ THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
+ enum thr_lock_type lock_type); ///< required
+ int optimize(THD* thd, HA_CHECK_OPT* check_opt);
+
+ /**
+ * Multi Range Read interface
+ */
+ int multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param,
+ uint n_ranges, uint mode, HANDLER_BUFFER *buf);
+ int multi_range_read_next(range_id_t *range_info);
+ ha_rows multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
+ void *seq_init_param,
+ uint n_ranges, uint *bufsz,
+ uint *flags, Cost_estimate *cost);
+ ha_rows multi_range_read_info(uint keyno, uint n_ranges, uint keys,
+ uint key_parts, uint *bufsz,
+ uint *flags, Cost_estimate *cost);
+ int multi_range_read_explain_info(uint mrr_mode, char *str, size_t size);
+
+ int reset(void) {ds_mrr.dsmrr_close(); return 0;}
+
+ /* Index condition pushdown implementation */
+// Item *idx_cond_push(uint keyno, Item* idx_cond);
+private:
+ DsMrr_impl ds_mrr;
+
+protected:
+ bool check_privileges(THD *thd, PTOS options, char *dbn);
+ MODE CheckMode(PGLOBAL g, THD *thd, MODE newmode, bool *chk, bool *cras);
+ char *GetDBfromName(const char *name);
+
+ // Members
+ static ulong num; // Tracable handler number
+ PCONNECT xp; // To user_connect associated class
+ ulong hnum; // The number of this handler
+ query_id_t valid_query_id; // The one when tdbp was allocated
+ query_id_t creat_query_id; // The one when handler was allocated
+ PTDB tdbp; // To table class object
+ PVAL sdvalin; // Used to convert date values
+ PVAL sdvalout; // Used to convert date values
+ bool istable; // True for table handler
+//char tname[64]; // The table name
+ MODE xmod; // Table mode
+ 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
+ bool mrr; // True when getting index positions
+ int indexing; // Type of indexing for CONNECT
+ int locked; // Table lock
+ THR_LOCK_DATA lock_data;
+
+public:
+ TABLE_SHARE *tshp; // Used by called tables
+ char *data_file_name;
+ char *index_file_name;
+ uint int_table_flags; // Inherited from MyISAM
+ bool enable_activate_all_index; // Inherited from MyISAM
+}; // end of ha_connect class definition
diff --git a/storage/connect/myconn.cpp b/storage/connect/myconn.cpp
index 3d0a3d86136..18c80f2b24e 100644
--- a/storage/connect/myconn.cpp
+++ b/storage/connect/myconn.cpp
@@ -47,9 +47,12 @@
#include "myconn.h"
extern "C" int trace;
+extern "C" int zconv;
extern MYSQL_PLUGIN_IMPORT uint mysqld_port;
extern MYSQL_PLUGIN_IMPORT char *mysqld_unix_port;
+DllExport void PushWarning(PGLOBAL, THD*, int level = 1);
+
// Returns the current used port
uint GetDefaultPort(void)
{
@@ -61,7 +64,7 @@ uint GetDefaultPort(void)
/* of a MySQL table or view. */
/* info = TRUE to get catalog column informations. */
/************************************************************************/
-PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db,
+PQRYRES MyColumns(PGLOBAL g, THD *thd, const char *host, const char *db,
const char *user, const char *pwd,
const char *table, const char *colpat,
int port, bool info)
@@ -75,7 +78,7 @@ PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db,
FLD_REM, FLD_NO, FLD_DEFAULT, FLD_EXTRA,
FLD_CHARSET};
unsigned int length[] = {0, 4, 16, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0};
- char *fld, *fmt, v, cmd[128], uns[16], zero[16];
+ char *fld, *colname, *chset, *fmt, v, cmd[128], uns[16], zero[16];
int i, n, nf, ncol = sizeof(buftyp) / sizeof(int);
int len, type, prec, rc, k = 0;
PQRYRES qrp;
@@ -144,23 +147,24 @@ PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db,
/**********************************************************************/
/* Now get the results into blocks. */
/**********************************************************************/
- for (i = 0; i < n; i++) {
- if ((rc = myc.Fetch(g, -1) == RC_FX)) {
+ for (i = 0; i < n; /*i++*/) {
+ if ((rc = myc.Fetch(g, -1)) == RC_FX) {
myc.Close();
return NULL;
- } else if (rc == RC_NF)
+ } else if (rc == RC_EF)
break;
// Get column name
- fld = myc.GetCharField(0);
+ colname = myc.GetCharField(0);
crp = qrp->Colresp; // Column_Name
- crp->Kdata->SetValue(fld, i);
+ crp->Kdata->SetValue(colname, i);
// Get type, type name, precision, unsigned and zerofill
+ chset = myc.GetCharField(2);
fld = myc.GetCharField(1);
prec = 0;
len = 0;
- v = 0;
+ v = (chset && !strcmp(chset, "binary")) ? 'B' : 0;
*uns = 0;
*zero = 0;
@@ -181,11 +185,28 @@ PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db,
} // endswitch nf
if ((type = MYSQLtoPLG(cmd, &v)) == TYPE_ERROR) {
- sprintf(g->Message, "Unsupported column type %s", cmd);
+ if (v == 'K') {
+ // Skip this column
+ sprintf(g->Message, "Column %s skipped (unsupported type %s)",
+ colname, cmd);
+ PushWarning(g, thd);
+ continue;
+ } // endif v
+
+ sprintf(g->Message, "Column %s unsupported type %s", colname, cmd);
myc.Close();
return NULL;
- } else if (type == TYPE_STRING)
- len = min(len, 4096);
+ } else if (type == TYPE_STRING) {
+ if (v == 'X') {
+ len = zconv;
+ sprintf(g->Message, "Column %s converted to varchar(%d)",
+ colname, len);
+ PushWarning(g, thd);
+ v = 'V';
+ } else
+ len = min(len, 4096);
+
+ } // endif type
qrp->Nblin++;
crp = crp->Next; // Data_Type
@@ -241,8 +262,10 @@ PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db,
crp->Kdata->SetValue(fld, i);
crp = crp->Next; // New (charset)
- fld = myc.GetCharField(2);
+ fld = chset;
crp->Kdata->SetValue(fld, i);
+
+ i++; // Can be skipped
} // endfor i
#if 0
@@ -284,7 +307,7 @@ PQRYRES SrcColumns(PGLOBAL g, const char *host, const char *db,
if (!port)
port = mysqld_port;
- if (!strnicmp(srcdef, "select ", 7)) {
+ if (!strnicmp(srcdef, "select ", 7)) {
query = (char *)PlugSubAlloc(g, NULL, strlen(srcdef) + 9);
strcat(strcpy(query, srcdef), " LIMIT 0");
} else
@@ -608,7 +631,7 @@ if (w)
/***********************************************************************/
void MYSQLC::DataSeek(my_ulonglong row)
{
- MYSQL_ROWS *tmp=0;
+ MYSQL_ROWS *tmp=0;
//DBUG_PRINT("info",("mysql_data_seek(%ld)",(long) row));
if (m_Res->data)
@@ -783,7 +806,7 @@ PQRYRES MYSQLC::GetResult(PGLOBAL g, bool pdb)
else {
if (!*row && crp->Nulls)
crp->Nulls[n] = '*'; // Null value
-
+
crp->Kdata->Reset(n);
} // endelse *row
}
@@ -880,7 +903,7 @@ void MYSQLC::DiscardResults(void)
while (!mysql_next_result(m_DB)) {
res = mysql_store_result(m_DB);
mysql_free_result(res);
- } // endwhile next result
+ } // endwhile next result
} // end of DiscardResults
#endif // 0
diff --git a/storage/connect/myconn.h b/storage/connect/myconn.h
index 856b6c73ef3..5bfa58ffb0c 100644
--- a/storage/connect/myconn.h
+++ b/storage/connect/myconn.h
@@ -34,7 +34,7 @@ typedef class MYSQLC *PMYC;
/***********************************************************************/
/* Prototypes of info functions. */
/***********************************************************************/
-PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db,
+PQRYRES MyColumns(PGLOBAL g, THD *thd, const char *host, const char *db,
const char *user, const char *pwd,
const char *table, const char *colpat,
int port, bool info);
diff --git a/storage/connect/mysql-test/connect/r/pivot.result b/storage/connect/mysql-test/connect/r/pivot.result
index 82b1e0a0b0b..4b39a21d3d9 100644
--- a/storage/connect/mysql-test/connect/r/pivot.result
+++ b/storage/connect/mysql-test/connect/r/pivot.result
@@ -229,7 +229,7 @@ DROP TABLE pets;
#
CREATE TABLE fruit (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
-`name` varchar(32) DEFAULT NULL,
+`name` varchar(32) NOT NULL,
`cnt` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=6 DEFAULT CHARSET=latin1;
diff --git a/storage/connect/mysql-test/connect/suite.pm b/storage/connect/mysql-test/connect/suite.pm
index 3bbeffca7d9..2dabbc82e7d 100644
--- a/storage/connect/mysql-test/connect/suite.pm
+++ b/storage/connect/mysql-test/connect/suite.pm
@@ -5,6 +5,11 @@ package My::Suite::Connect;
return "No CONNECT engine" unless $ENV{HA_CONNECT_SO} or
$::mysqld_variables{'connect'} eq "ON";
+# RECOMPILE_FOR_EMBEDDED also means that a plugin
+# cannot be dynamically loaded into embedded
+return "Not run for embedded server" if $::opt_embedded_server and
+ $ENV{HA_CONNECT_SO};
+
sub is_default { 1 }
bless { };
diff --git a/storage/connect/mysql-test/connect/t/pivot.test b/storage/connect/mysql-test/connect/t/pivot.test
index 3212496a220..d26e6cec628 100644
--- a/storage/connect/mysql-test/connect/t/pivot.test
+++ b/storage/connect/mysql-test/connect/t/pivot.test
@@ -1,163 +1,163 @@
--- source include/not_embedded.inc
-
-let $MYSQLD_DATADIR= `select @@datadir`;
-let $PORT= `select @@port`;
---copy_file $MTR_SUITE_DIR/std_data/expenses.txt $MYSQLD_DATADIR/test/expenses.txt
-
---echo #
---echo # Testing the PIVOT table type
---echo #
-CREATE TABLE expenses (
-Who CHAR(10) NOT NULL,
-Week INT(2) NOT NULL,
-What CHAR(12) NOT NULL,
-Amount DOUBLE(8,2))
-ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='expenses.txt' ENDING=2;
-SELECT * FROM expenses;
-
---echo #
---echo # Pivoting from What
---echo #
-CREATE TABLE pivex (
-Who CHAR(10) NOT NULL,
-Week INT(2) NOT NULL,
-Beer DOUBLE(8,2) FLAG=1,
-Car DOUBLE(8,2) FLAG=1,
-Food DOUBLE(8,2) FLAG=1)
-ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=expenses;
---replace_result $PORT PORT
---eval ALTER TABLE pivex OPTION_LIST='port=$PORT'
-SELECT * FROM pivex;
-
---echo #
---echo # Restricting the columns in a Pivot Table
---echo #
-ALTER TABLE pivex DROP COLUMN week;
-SELECT * FROM pivex;
-
---echo #
---echo # Using a source definition
---echo #
-DROP TABLE pivex;
-CREATE TABLE pivex (
-Who CHAR(10) NOT NULL,
-Week INT(2) NOT NULL,
-Beer DOUBLE(8,2) FLAG=1,
-Car DOUBLE(8,2) FLAG=1,
-Food DOUBLE(8,2) FLAG=1)
-ENGINE=CONNECT TABLE_TYPE=PIVOT
-SRCDEF='select who, week, what, sum(amount) as amount from expenses where week in (4,5) group by who, week, what';
---replace_result $PORT PORT
---eval ALTER TABLE pivex OPTION_LIST='PivotCol=what,FncCol=amount,port=$PORT'
-SELECT * FROM pivex;
-
---echo #
---echo # Pivoting from Week
---echo #
-DROP TABLE pivex;
-CREATE TABLE pivex (
-Who CHAR(10) NOT NULL,
-What CHAR(12) NOT NULL,
-`3` DOUBLE(8,2) FLAG=1,
-`4` DOUBLE(8,2) FLAG=1,
-`5` DOUBLE(8,2) FLAG=1)
-ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=expenses;
---replace_result $PORT PORT
---eval ALTER TABLE pivex OPTION_LIST='PivotCol=Week,port=$PORT'
-SELECT * FROM pivex;
-
---echo #
---echo # Using scalar functions and expresssions
---echo #
-DROP TABLE pivex;
-CREATE TABLE pivex (
-Who CHAR(10) NOT NULL,
-What CHAR(12) NOT NULL,
-First DOUBLE(8,2) FLAG=1,
-Middle DOUBLE(8,2) FLAG=1,
-Last DOUBLE(8,2) FLAG=1)
-ENGINE=CONNECT TABLE_TYPE=PIVOT
-SRCDEF='select who, what, case when week=3 then ''First'' when week=5 then ''Last'' else ''Middle'' end as wk, sum(amount) * 6.56 as amnt from expenses group by who, what, wk';
---replace_result $PORT PORT
---eval ALTER TABLE pivex OPTION_LIST='PivotCol=wk,FncCol=amnt,port=$PORT'
-SELECT * FROM pivex;
-DROP TABLE pivex;
-DROP TABLE expenses;
-
---echo #
---echo # Make the PETS table
---echo #
-CREATE TABLE pets (
-Name VARCHAR(12) NOT NULL,
-Race CHAR(6) NOT NULL,
-Number INT NOT NULL) ENGINE=MYISAM;
-INSERT INTO pets VALUES('John','dog',2);
-INSERT INTO pets VALUES('Bill','cat',1);
-INSERT INTO pets VALUES('Mary','dog',1);
-INSERT INTO pets VALUES('Mary','cat',1);
-INSERT INTO pets VALUES('Lisbeth','rabbit',2);
-INSERT INTO pets VALUES('Kevin','cat',2);
-INSERT INTO pets VALUES('Kevin','bird',6);
-INSERT INTO pets VALUES('Donald','dog',1);
-INSERT INTO pets VALUES('Donald','fish',3);
-SELECT * FROM pets;
-
---echo #
---echo # Pivot the PETS table
---echo #
-CREATE TABLE pivet (
-name VARCHAR(12) NOT NULL,
-dog INT NOT NULL DEFAULT 0 FLAG=1,
-cat INT NOT NULL DEFAULT 0 FLAG=1,
-rabbit INT NOT NULL DEFAULT 0 FLAG=1,
-bird INT NOT NULL DEFAULT 0 FLAG=1,
-fish INT NOT NULL DEFAULT 0 FLAG=1)
-ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=pets OPTION_LIST='PivotCol=race,groupby=1';
-SELECT * FROM pivet;
-DROP TABLE pivet;
-
---echo #
---echo # Testing the "data" column list
---echo #
-CREATE TABLE pivet (
-name VARCHAR(12) NOT NULL,
-dog INT NOT NULL DEFAULT 0 FLAG=1,
-cat INT NOT NULL DEFAULT 0 FLAG=1)
-ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=pets OPTION_LIST='PivotCol=race,groupby=1';
---error ER_GET_ERRMSG
-SELECT * FROM pivet;
-ALTER TABLE pivet OPTION_LIST='PivotCol=race,groupby=1,accept=1';
-SELECT * FROM pivet;
-DROP TABLE pivet;
-
---echo #
---echo # Adding a "dump" column
---echo #
-CREATE TABLE pivet (
-name VARCHAR(12) NOT NULL,
-dog INT NOT NULL DEFAULT 0 FLAG=1,
-cat INT NOT NULL DEFAULT 0 FLAG=1,
-other INT NOT NULL DEFAULT 0 FLAG=2)
-ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=pets OPTION_LIST='PivotCol=race,groupby=1';
-SELECT * FROM pivet;
-
-DROP TABLE pivet;
-DROP TABLE pets;
-
---echo #
---echo # MDEV-5734
---echo #
-CREATE TABLE fruit (
- `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
- `name` varchar(32) DEFAULT NULL,
- `cnt` int(11) DEFAULT NULL,
- PRIMARY KEY (`id`)
-) ENGINE=MyISAM AUTO_INCREMENT=6 DEFAULT CHARSET=latin1;
-INSERT INTO fruit VALUES (1,'apple',1),(2,'banana',1),(3,'apple',2),(4,'cherry',4),(5,'durazno',2);
-SELECT * FROM fruit;
-CREATE TABLE fruit_pivot ENGINE=CONNECT TABLE_TYPE=pivot TABNAME=fruit;
-SELECT * FROM fruit_pivot;
-
-DROP TABLE fruit_pivot;
-DROP TABLE fruit;
---remove_file $MYSQLD_DATADIR/test/expenses.txt
+-- source include/not_embedded.inc
+
+let $MYSQLD_DATADIR= `select @@datadir`;
+let $PORT= `select @@port`;
+--copy_file $MTR_SUITE_DIR/std_data/expenses.txt $MYSQLD_DATADIR/test/expenses.txt
+
+--echo #
+--echo # Testing the PIVOT table type
+--echo #
+CREATE TABLE expenses (
+Who CHAR(10) NOT NULL,
+Week INT(2) NOT NULL,
+What CHAR(12) NOT NULL,
+Amount DOUBLE(8,2))
+ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='expenses.txt' ENDING=2;
+SELECT * FROM expenses;
+
+--echo #
+--echo # Pivoting from What
+--echo #
+CREATE TABLE pivex (
+Who CHAR(10) NOT NULL,
+Week INT(2) NOT NULL,
+Beer DOUBLE(8,2) FLAG=1,
+Car DOUBLE(8,2) FLAG=1,
+Food DOUBLE(8,2) FLAG=1)
+ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=expenses;
+--replace_result $PORT PORT
+--eval ALTER TABLE pivex OPTION_LIST='port=$PORT'
+SELECT * FROM pivex;
+
+--echo #
+--echo # Restricting the columns in a Pivot Table
+--echo #
+ALTER TABLE pivex DROP COLUMN week;
+SELECT * FROM pivex;
+
+--echo #
+--echo # Using a source definition
+--echo #
+DROP TABLE pivex;
+CREATE TABLE pivex (
+Who CHAR(10) NOT NULL,
+Week INT(2) NOT NULL,
+Beer DOUBLE(8,2) FLAG=1,
+Car DOUBLE(8,2) FLAG=1,
+Food DOUBLE(8,2) FLAG=1)
+ENGINE=CONNECT TABLE_TYPE=PIVOT
+SRCDEF='select who, week, what, sum(amount) as amount from expenses where week in (4,5) group by who, week, what';
+--replace_result $PORT PORT
+--eval ALTER TABLE pivex OPTION_LIST='PivotCol=what,FncCol=amount,port=$PORT'
+SELECT * FROM pivex;
+
+--echo #
+--echo # Pivoting from Week
+--echo #
+DROP TABLE pivex;
+CREATE TABLE pivex (
+Who CHAR(10) NOT NULL,
+What CHAR(12) NOT NULL,
+`3` DOUBLE(8,2) FLAG=1,
+`4` DOUBLE(8,2) FLAG=1,
+`5` DOUBLE(8,2) FLAG=1)
+ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=expenses;
+--replace_result $PORT PORT
+--eval ALTER TABLE pivex OPTION_LIST='PivotCol=Week,port=$PORT'
+SELECT * FROM pivex;
+
+--echo #
+--echo # Using scalar functions and expresssions
+--echo #
+DROP TABLE pivex;
+CREATE TABLE pivex (
+Who CHAR(10) NOT NULL,
+What CHAR(12) NOT NULL,
+First DOUBLE(8,2) FLAG=1,
+Middle DOUBLE(8,2) FLAG=1,
+Last DOUBLE(8,2) FLAG=1)
+ENGINE=CONNECT TABLE_TYPE=PIVOT
+SRCDEF='select who, what, case when week=3 then ''First'' when week=5 then ''Last'' else ''Middle'' end as wk, sum(amount) * 6.56 as amnt from expenses group by who, what, wk';
+--replace_result $PORT PORT
+--eval ALTER TABLE pivex OPTION_LIST='PivotCol=wk,FncCol=amnt,port=$PORT'
+SELECT * FROM pivex;
+DROP TABLE pivex;
+DROP TABLE expenses;
+
+--echo #
+--echo # Make the PETS table
+--echo #
+CREATE TABLE pets (
+Name VARCHAR(12) NOT NULL,
+Race CHAR(6) NOT NULL,
+Number INT NOT NULL) ENGINE=MYISAM;
+INSERT INTO pets VALUES('John','dog',2);
+INSERT INTO pets VALUES('Bill','cat',1);
+INSERT INTO pets VALUES('Mary','dog',1);
+INSERT INTO pets VALUES('Mary','cat',1);
+INSERT INTO pets VALUES('Lisbeth','rabbit',2);
+INSERT INTO pets VALUES('Kevin','cat',2);
+INSERT INTO pets VALUES('Kevin','bird',6);
+INSERT INTO pets VALUES('Donald','dog',1);
+INSERT INTO pets VALUES('Donald','fish',3);
+SELECT * FROM pets;
+
+--echo #
+--echo # Pivot the PETS table
+--echo #
+CREATE TABLE pivet (
+name VARCHAR(12) NOT NULL,
+dog INT NOT NULL DEFAULT 0 FLAG=1,
+cat INT NOT NULL DEFAULT 0 FLAG=1,
+rabbit INT NOT NULL DEFAULT 0 FLAG=1,
+bird INT NOT NULL DEFAULT 0 FLAG=1,
+fish INT NOT NULL DEFAULT 0 FLAG=1)
+ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=pets OPTION_LIST='PivotCol=race,groupby=1';
+SELECT * FROM pivet;
+DROP TABLE pivet;
+
+--echo #
+--echo # Testing the "data" column list
+--echo #
+CREATE TABLE pivet (
+name VARCHAR(12) NOT NULL,
+dog INT NOT NULL DEFAULT 0 FLAG=1,
+cat INT NOT NULL DEFAULT 0 FLAG=1)
+ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=pets OPTION_LIST='PivotCol=race,groupby=1';
+--error ER_GET_ERRMSG
+SELECT * FROM pivet;
+ALTER TABLE pivet OPTION_LIST='PivotCol=race,groupby=1,accept=1';
+SELECT * FROM pivet;
+DROP TABLE pivet;
+
+--echo #
+--echo # Adding a "dump" column
+--echo #
+CREATE TABLE pivet (
+name VARCHAR(12) NOT NULL,
+dog INT NOT NULL DEFAULT 0 FLAG=1,
+cat INT NOT NULL DEFAULT 0 FLAG=1,
+other INT NOT NULL DEFAULT 0 FLAG=2)
+ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=pets OPTION_LIST='PivotCol=race,groupby=1';
+SELECT * FROM pivet;
+
+DROP TABLE pivet;
+DROP TABLE pets;
+
+--echo #
+--echo # MDEV-5734
+--echo #
+CREATE TABLE fruit (
+ `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+ `name` varchar(32) NOT NULL,
+ `cnt` int(11) DEFAULT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=MyISAM AUTO_INCREMENT=6 DEFAULT CHARSET=latin1;
+INSERT INTO fruit VALUES (1,'apple',1),(2,'banana',1),(3,'apple',2),(4,'cherry',4),(5,'durazno',2);
+SELECT * FROM fruit;
+CREATE TABLE fruit_pivot ENGINE=CONNECT TABLE_TYPE=pivot TABNAME=fruit;
+SELECT * FROM fruit_pivot;
+
+DROP TABLE fruit_pivot;
+DROP TABLE fruit;
+--remove_file $MYSQLD_DATADIR/test/expenses.txt
diff --git a/storage/connect/myutil.cpp b/storage/connect/myutil.cpp
index ea694389eaf..0d9a1e2fe16 100644
--- a/storage/connect/myutil.cpp
+++ b/storage/connect/myutil.cpp
@@ -1,9 +1,9 @@
/************** MyUtil C++ Program Source Code File (.CPP) **************/
/* PROGRAM NAME: MYUTIL */
/* ------------- */
-/* Version 1.1 */
+/* Version 1.2 */
/* */
-/* Author Olivier BERTRAND 2013 */
+/* Author Olivier BERTRAND 2014 */
/* */
/* WHAT THIS PROGRAM DOES: */
/* ----------------------- */
@@ -26,6 +26,8 @@
#include "myutil.h"
#define DLL_EXPORT // Items are exported from this DLL
+extern "C" int xconv;
+
/************************************************************************/
/* Convert from MySQL type name to PlugDB type number */
/************************************************************************/
@@ -38,8 +40,7 @@ int MYSQLtoPLG(char *typname, char *var)
type = TYPE_INT;
else if (!stricmp(typname, "smallint"))
type = TYPE_SHORT;
- else if (!stricmp(typname, "char") || !stricmp(typname, "varchar") ||
- !stricmp(typname, "text") || !stricmp(typname, "blob"))
+ else if (!stricmp(typname, "char") || !stricmp(typname, "varchar"))
type = TYPE_STRING;
else if (!stricmp(typname, "double") || !stricmp(typname, "float") ||
!stricmp(typname, "real"))
@@ -54,7 +55,20 @@ int MYSQLtoPLG(char *typname, char *var)
type = TYPE_BIGINT;
else if (!stricmp(typname, "tinyint"))
type = TYPE_TINY;
- else
+ else if (!stricmp(typname, "text") && var) {
+ switch (xconv) {
+ case 1:
+ type = TYPE_STRING;
+ *var = 'X';
+ break;
+ case 2:
+ *var = 'K';
+ default:
+ type = TYPE_ERROR;
+ } // endswitch xconv
+
+ return type;
+ } else
type = TYPE_ERROR;
if (var) {
@@ -71,9 +85,11 @@ int MYSQLtoPLG(char *typname, char *var)
else if (!stricmp(typname, "year"))
*var = 'Y';
- } else if (type == TYPE_STRING && stricmp(typname, "char"))
+ } else if (type == TYPE_STRING && !stricmp(typname, "varchar"))
// This is to make the difference between CHAR and VARCHAR
*var = 'V';
+ else if (type == TYPE_ERROR && xconv == 2)
+ *var = 'K';
else
*var = 0;
@@ -196,34 +212,50 @@ int MYSQLtoPLG(int mytype, char *var)
#if !defined(ALPHA)
case MYSQL_TYPE_VARCHAR:
#endif // !ALPHA)
+ case MYSQL_TYPE_STRING:
+ type = TYPE_STRING;
+ break;
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_TINY_BLOB:
case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_LONG_BLOB:
- case MYSQL_TYPE_STRING:
- type = TYPE_STRING;
- break;
+ if (var) {
+ switch (xconv) {
+ case 1:
+ if (*var != 'B') {
+ // This is a TEXT column
+ type = TYPE_STRING;
+ *var = 'X';
+ } else
+ type = TYPE_ERROR;
+
+ break;
+ case 2:
+ *var = 'K'; // Skip
+ default:
+ type = TYPE_ERROR;
+ } // endswitch xconv
+
+ return type;
+ } // endif var
+
default:
type = TYPE_ERROR;
} // endswitch mytype
if (var) switch (mytype) {
// This is to make the difference between CHAR and VARCHAR
- case MYSQL_TYPE_VAR_STRING:
#if !defined(ALPHA)
case MYSQL_TYPE_VARCHAR:
#endif // !ALPHA)
- case MYSQL_TYPE_BLOB:
- case MYSQL_TYPE_TINY_BLOB:
- case MYSQL_TYPE_MEDIUM_BLOB:
- case MYSQL_TYPE_LONG_BLOB: *var = 'V'; break;
+ case MYSQL_TYPE_VAR_STRING: *var = 'V'; break;
// This is to make the difference between temporal values
- case MYSQL_TYPE_TIMESTAMP: *var = 'S'; break;
- case MYSQL_TYPE_DATE: *var = 'D'; break;
- case MYSQL_TYPE_DATETIME: *var = 'A'; break;
- case MYSQL_TYPE_YEAR: *var = 'Y'; break;
- case MYSQL_TYPE_TIME: *var = 'T'; break;
- default: *var = 0;
+ case MYSQL_TYPE_TIMESTAMP: *var = 'S'; break;
+ case MYSQL_TYPE_DATE: *var = 'D'; break;
+ case MYSQL_TYPE_DATETIME: *var = 'A'; break;
+ case MYSQL_TYPE_YEAR: *var = 'Y'; break;
+ case MYSQL_TYPE_TIME: *var = 'T'; break;
+ default: *var = 0;
} // endswitch mytype
return type;
diff --git a/storage/connect/osutil.c b/storage/connect/osutil.c
index 3c1ca0147c6..66985847ce7 100644
--- a/storage/connect/osutil.c
+++ b/storage/connect/osutil.c
@@ -16,6 +16,7 @@ my_bool CloseFileHandle(HANDLE h)
#include <sys/stat.h>
#include <ctype.h>
#include <fcntl.h>
+#include <pwd.h>
extern FILE *debug;
@@ -172,16 +173,23 @@ char *_fullpath(char *absPath, const char *relPath, size_t maxLength)
// Fixme
char *p;
- if( *relPath == '\\' || *relPath == '/' ) {
+ if ( *relPath == '\\' || *relPath == '/' ) {
strncpy(absPath, relPath, maxLength);
- } else if(*relPath == '~') {
+ } else if (*relPath == '~') {
// get the path to the home directory
- // Fixme
- strncpy(absPath, relPath, maxLength);
- } else {
+ struct passwd *pw = getpwuid(getuid());
+ const char *homedir = pw->pw_dir;
+
+ if (homedir)
+ strcat(strncpy(absPath, homedir, maxLength), relPath + 1);
+ else
+ strncpy(absPath, relPath, maxLength);
+
+ } else {
char buff[2*_MAX_PATH];
- assert(getcwd(buff, _MAX_PATH) != NULL);
+ p= getcwd(buff, _MAX_PATH);
+ assert(p);
strcat(buff,"/");
strcat(buff, relPath);
strncpy(absPath, buff, maxLength);
diff --git a/storage/connect/plgdbsem.h b/storage/connect/plgdbsem.h
index 0fe9e20e390..0075b8ae5cc 100644
--- a/storage/connect/plgdbsem.h
+++ b/storage/connect/plgdbsem.h
@@ -1,598 +1,599 @@
-/************** PlgDBSem H Declares Source Code File (.H) **************/
-/* Name: PLGDBSEM.H Version 3.6 */
-/* */
-/* (C) Copyright to the author Olivier BERTRAND 1998-2014 */
-/* */
-/* This file contains the PlugDB++ application type definitions. */
-/***********************************************************************/
-
-/***********************************************************************/
-/* Include required application header files */
-/***********************************************************************/
-#include "checklvl.h"
-
-/***********************************************************************/
-/* DB Constant definitions. */
-/***********************************************************************/
-#if defined(FRENCH)
-#define DEFAULT_LOCALE "French"
-#else // !FRENCH
-#define DEFAULT_LOCALE "English"
-#endif // !FRENCH
-
-#define DOS_MAX_PATH 144 /* Must be the same across systems */
-#define DOS_BUFF_LEN 100 /* Number of lines in binary file buffer */
-#undef DOMAIN /* For Unix version */
-
-enum BLKTYP {TYPE_TABLE = 50, /* Table Name/Srcdef/... Block */
- TYPE_COLUMN = 51, /* Column Name/Qualifier Block */
- TYPE_TDB = 53, /* Table Description Block */
- TYPE_COLBLK = 54, /* Column Description Block */
- TYPE_FILTER = 55, /* Filter Description Block */
- TYPE_ARRAY = 63, /* General array type */
- TYPE_PSZ = 64, /* Pointer to String ended by 0 */
- TYPE_SQL = 65, /* Pointer to SQL block */
- TYPE_XOBJECT = 69, /* Extended DB object */
- TYPE_COLCRT = 71, /* Column creation block */
- TYPE_CONST = 72, /* Constant */
-
-/*-------------------- type tokenized string --------------------------*/
- TYPE_DATE = 8, /* Timestamp */
-/*-------------------- additional values used by LNA ------------------*/
- TYPE_COLIST = 14, /* Column list */
- TYPE_COL = 41, /* Column */
-/*-------------------- types used by scalar functions -----------------*/
- TYPE_NUM = 12,
- TYPE_UNDEF = 13,
-/*-------------------- file blocks used when closing ------------------*/
- TYPE_FB_FILE = 22, /* File block (stream) */
- TYPE_FB_MAP = 23, /* Mapped file block (storage) */
- TYPE_FB_HANDLE = 24, /* File block (handle) */
- TYPE_FB_XML = 21, /* DOM XML file block */
- TYPE_FB_XML2 = 27}; /* libxml2 XML file block */
-
-enum TABTYPE {TAB_UNDEF = 0, /* Table of undefined type */
- TAB_DOS = 1, /* Fixed column offset, variable LRECL */
- TAB_FIX = 2, /* Fixed column offset, fixed LRECL */
- TAB_BIN = 3, /* Like FIX but can have binary fields */
- TAB_CSV = 4, /* DOS files with CSV records */
- TAB_FMT = 5, /* DOS files with formatted recordss */
- TAB_DBF = 6, /* DBF Dbase or Foxpro files */
- TAB_XML = 7, /* XML or HTML files */
- TAB_INI = 8, /* INI or CFG files */
- TAB_VEC = 9, /* Vector column arrangement */
- TAB_ODBC = 10, /* Table accessed via (unix)ODBC */
- TAB_MYSQL = 11, /* MySQL table accessed via MySQL API */
- TAB_DIR = 12, /* Returns a list of files */
- TAB_MAC = 13, /* MAC address (Windows only) */
- TAB_WMI = 14, /* WMI tables (Windows only) */
- TAB_TBL = 15, /* Collection of CONNECT tables */
- TAB_OEM = 16, /* OEM implemented table */
- TAB_XCL = 17, /* XCL table */
- TAB_OCCUR = 18, /* OCCUR table */
- TAB_PRX = 19, /* Proxy (catalog) table */
- TAB_PLG = 20, /* PLG NIY */
- TAB_PIVOT = 21, /* PIVOT NIY */
- TAB_JCT = 22, /* Junction tables NIY */
- TAB_DMY = 23, /* DMY Dummy tables NIY */
- TAB_NIY = 24}; /* Table not implemented yet */
-
-enum AMT {TYPE_AM_ERROR = 0, /* Type not defined */
- TYPE_AM_ROWID = 1, /* ROWID type (special column) */
- TYPE_AM_FILID = 2, /* FILEID type (special column) */
- TYPE_AM_TAB = 3, /* Table (any type) */
- TYPE_AM_VIEW = 4, /* VIEW (any type) */
- TYPE_AM_SRVID = 5, /* SERVID type (special column) */
- TYPE_AM_TABID = 6, /* TABID type (special column) */
- TYPE_AM_CNSID = 7, /* CONSTID type (special column) */
- TYPE_AM_COUNT = 10, /* CPT AM type no (count table) */
- TYPE_AM_DCD = 20, /* Decode access method type no */
- TYPE_AM_CMS = 30, /* CMS access method type no */
- TYPE_AM_MAP = 32, /* MAP access method type no */
- TYPE_AM_FMT = 33, /* DOS files with formatted recs */
- TYPE_AM_CSV = 34, /* DOS files with CSV records */
- TYPE_AM_MCV = 35, /* MAP files with CSV records */
- TYPE_AM_DOS = 36, /* DOS am with Lrecl = V */
- TYPE_AM_FIX = 38, /* DOS am with Lrecl = F */
- TYPE_AM_BIN = 39, /* DOS am with Lrecl = B */
- TYPE_AM_VCT = 40, /* VCT access method type no */
- TYPE_AM_VMP = 43, /* VMP access method type no */
- TYPE_AM_QRY = 50, /* QRY access method type no */
- TYPE_AM_QRS = 51, /* QRYRES access method type no */
- TYPE_AM_SQL = 60, /* SQL VIEW access method type */
- TYPE_AM_PLG = 70, /* PLG access method type no */
- TYPE_AM_PLM = 71, /* PDM access method type no */
- TYPE_AM_DOM = 80, /* DOM access method type no */
- TYPE_AM_DIR = 90, /* DIR access method type no */
- TYPE_AM_ODBC = 100, /* ODBC access method type no */
- TYPE_AM_XDBC = 101, /* XDBC access method type no */
- TYPE_AM_OEM = 110, /* OEM access method type no */
- TYPE_AM_TBL = 115, /* TBL access method type no */
- TYPE_AM_PIVOT = 120, /* PIVOT access method type no */
- TYPE_AM_SRC = 121, /* PIVOT multiple column type no */
- TYPE_AM_FNC = 122, /* PIVOT source column type no */
- TYPE_AM_XCOL = 124, /* XCOL access method type no */
- TYPE_AM_XML = 127, /* XML access method type no */
- TYPE_AM_OCCUR = 128, /* OCCUR access method type no */
- TYPE_AM_PRX = 129, /* PROXY access method type no */
- TYPE_AM_XTB = 130, /* SYS table access method type */
- TYPE_AM_BLK = 131, /* BLK access method type no */
- TYPE_AM_ZIP = 132, /* ZIP access method type no */
- TYPE_AM_ZLIB = 133, /* ZLIB access method type no */
- TYPE_AM_MAC = 137, /* MAC table access method type */
- TYPE_AM_WMI = 139, /* WMI table access method type */
- TYPE_AM_XCL = 140, /* SYS column access method type */
- TYPE_AM_INI = 150, /* INI files access method */
- TYPE_AM_TFC = 155, /* TFC (Circa) (Fuzzy compare) */
- TYPE_AM_DBF = 160, /* DBF Dbase files am type no */
- TYPE_AM_JCT = 170, /* Junction tables am type no */
- TYPE_AM_DMY = 172, /* DMY Dummy tables am type no */
- TYPE_AM_SET = 180, /* SET Set tables am type no */
- TYPE_AM_MYSQL = 192, /* MYSQL access method type no */
- TYPE_AM_MYX = 193, /* MYSQL EXEC access method type */
- TYPE_AM_CAT = 195, /* Catalog access method type no */
- TYPE_AM_OUT = 200}; /* Output relations (storage) */
-
-enum RECFM {RECFM_NAF = -2, /* Not a file */
- RECFM_OEM = -1, /* OEM file access method */
- RECFM_VAR = 0, /* Varying length DOS files */
- RECFM_FIX = 1, /* Fixed length DOS files */
- RECFM_BIN = 2, /* Binary DOS files (also fixed) */
- RECFM_VCT = 3, /* VCT formatted files */
- RECFM_ODBC = 4, /* Table accessed via ODBC */
- RECFM_PLG = 5, /* Table accessed via PLGconn */
- RECFM_DBF = 6}; /* DBase formatted file */
-
-enum MISC {DB_TABNO = 1, /* DB routines in Utility Table */
- MAX_MULT_KEY = 10, /* Max multiple key number */
- NAM_LEN = 128, /* Length of col and tab names */
- ARRAY_SIZE = 50, /* Default array block size */
-// MAXRES = 500, /* Default maximum result lines */
-// MAXLIN = 10000, /* Default maximum data lines */
- MAXBMP = 32}; /* Default XDB2 max bitmap size */
-
-#if 0
-enum ALGMOD {AMOD_AUTO = 0, /* PLG chooses best algorithm */
- AMOD_SQL = 1, /* Use SQL algorithm */
- AMOD_QRY = 2}; /* Use QUERY algorithm */
-#endif // 0
-
-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 */
- MODE_INSERT = 40, /* Input/Output mode */
- MODE_DELETE = 50, /* Input/Output mode */
- MODE_ALTER = 60}; /* alter mode */
-
-#if !defined(RC_OK_DEFINED)
-#define RC_OK_DEFINED
-enum RCODE {RC_OK = 0, /* No error return code */
- RC_NF = 1, /* Not found return code */
- RC_EF = 2, /* End of file return code */
- RC_FX = 3, /* Error return code */
- RC_INFO = 4}; /* Success with info */
-#endif // !RC_OK_DEFINED
-
-enum OPVAL {OP_EQ = 1, /* Filtering operator = */
- OP_NE = 2, /* Filtering operator != */
- OP_GT = 3, /* Filtering operator > */
- OP_GE = 4, /* Filtering operator >= */
- OP_LT = 5, /* Filtering operator < */
- OP_LE = 6, /* Filtering operator <= */
- OP_IN = 7, /* Filtering operator IN */
- OP_NULL = 8, /* Filtering operator IS NULL */
- OP_EXIST = 9, /* Filtering operator EXISTS */
- OP_LIKE = 10, /* Filtering operator LIKE */
- OP_LOJ = -1, /* Filter op LEFT OUTER JOIN */
- OP_ROJ = -2, /* Filter op RIGHT OUTER JOIN */
- OP_DTJ = -3, /* Filter op DISTINCT JOIN */
- OP_XX = 11, /* Filtering operator unknown */
- OP_AND = 12, /* Filtering operator AND */
- OP_OR = 13, /* Filtering operator OR */
- OP_CNC = 14, /* Expression Concat operator */
- OP_NOT = 15, /* Filtering operator NOT */
- OP_SEP = 20, /* Filtering separator */
- OP_ADD = 16, /* Expression Add operator */
- OP_SUB = 17, /* Expression Substract operator */
- OP_MULT = 18, /* Expression Multiply operator */
- OP_DIV = 19, /* Expression Divide operator */
- OP_NOP = 21, /* Scalar function is nopped */
- OP_NUM = 22, /* Scalar function Op Num */
- OP_ABS = 23, /* Scalar function Op Abs */
- OP_MAX = 24, /* Scalar function Op Max */
- OP_MIN = 25, /* Scalar function Op Min */
- OP_CEIL = 26, /* Scalar function Op Ceil */
- OP_FLOOR = 27, /* Scalar function Op Floor */
- OP_MOD = 28, /* Scalar function Op Mod */
- OP_ROUND = 29, /* Scalar function Op Round */
- OP_SIGN = 30, /* Scalar function Op Sign */
- OP_LEN = 31, /* Scalar function Op Len */
- OP_INSTR = 32, /* Scalar function Op Instr */
- OP_LEFT = 33, /* Scalar function Op Left */
- OP_RIGHT = 34, /* Scalar function Op Right */
- OP_ASCII = 35, /* Scalar function Op Ascii */
- OP_EXP = 36, /* Scalar function Op Exp */
- OP_LN = 37, /* Scalar function Op Ln */
- OP_LOG = 38, /* Scalar function Op Log */
- OP_POWER = 39, /* Scalar function Op Power */
- OP_SQRT = 40, /* Scalar function Op Sqrt */
- OP_COS = 41, /* Scalar function Op Cos */
- OP_COSH = 42, /* Scalar function Op Cosh */
- OP_SIN = 43, /* Scalar function Op Sin */
- OP_SINH = 44, /* Scalar function Op Sinh */
- OP_TAN = 45, /* Scalar function Op Tan */
- OP_TANH = 46, /* Scalar function Op Tanh */
- OP_USER = 47, /* Scalar function Op User */
- OP_CHAR = 48, /* Scalar function Op Char */
- OP_UPPER = 49, /* Scalar function Op Upper */
- OP_LOWER = 50, /* Scalar function Op Lower */
- OP_RPAD = 51, /* Scalar function Op Rpad */
- OP_LPAD = 52, /* Scalar function Op Lpad */
- OP_LTRIM = 53, /* Scalar function Op Ltrim */
- OP_RTRIM = 54, /* Scalar function Op Rtrim */
- OP_REPL = 55, /* Scalar function Op Replace */
- OP_SUBST = 56, /* Scalar function Op Substr */
- OP_LJUST = 57, /* Scalar function Op Ljustify */
- OP_RJUST = 58, /* Scalar function Op Rjustify */
- OP_CJUST = 59, /* Scalar function Op Cjustify */
- OP_ENCODE = 60, /* Scalar function Op Encode */
- OP_DECODE = 61, /* Scalar function Op Decode */
- OP_SEQU = 62, /* Scalar function Op Sequence */
- OP_IF = 63, /* Scalar function Op If */
- OP_STRING = 64, /* Scalar function Op String */
- OP_TOKEN = 65, /* Scalar function Op Token */
- OP_SNDX = 66, /* Scalar function Op Soundex */
- OP_DATE = 67, /* Scalar function Op Date */
- OP_MDAY = 68, /* Scalar function Op Month Day */
- OP_MONTH = 69, /* Scalar function Op Month of */
- OP_YEAR = 70, /* Scalar function Op Year of */
- OP_WDAY = 71, /* Scalar function Op Week Day */
- OP_YDAY = 72, /* Scalar function Op Year Day */
- OP_DBTWN = 73, /* Scalar function Op Days betwn */
- OP_MBTWN = 74, /* Scalar function Op Months btw */
- OP_YBTWN = 75, /* Scalar function Op Years btwn */
- OP_ADDAY = 76, /* Scalar function Op Add Days */
- OP_ADDMTH = 77, /* Scalar function Op Add Months */
- OP_ADDYR = 78, /* Scalar function Op Add Years */
- OP_NXTDAY = 79, /* Scalar function Op Next Day */
- OP_SYSDT = 80, /* Scalar function Op SysDate */
- OP_DELTA = 81, /* Scalar function Op Delta */
- OP_LAST = 82, /* Scalar function Op Last */
- OP_IFF = 83, /* Scalar function Op Iff */
- OP_MAVG = 84, /* Scalar function Op Moving Avg */
- OP_VWAP = 85, /* Scalar function Op VWAP */
- OP_TIME = 86, /* Scalar function Op TIME */
- OP_SETLEN = 87, /* Scalar function Op Set Length */
- OP_TRANSL = 88, /* Scalar function Op Translate */
- OP_BITAND = 89, /* Expression BitAnd operator */
- OP_BITOR = 90, /* Expression BitOr operator */
- OP_BITXOR = 91, /* Expression XOR operator */
- OP_BITNOT = 92, /* Expression Complement operator*/
- OP_CNTIN = 93, /* Scalar function Count In */
- OP_FDISK = 94, /* Scalar function Disk of fileid*/
- OP_FPATH = 95, /* Scalar function Path of fileid*/
- OP_FNAME = 96, /* Scalar function Name of fileid*/
- OP_FTYPE = 97, /* Scalar function Type of fileid*/
- OP_XDATE = 98, /* Scalar function Op Fmt Date */
- OP_SWITCH = 99, /* Scalar function Op Switch */
- OP_EXIT = 100, /* Scalar function Op Exit */
- OP_LIT = 101, /* Scalar function Op Literal */
- OP_LOCALE = 102, /* Scalar function Op Locale */
- OP_FRNCH = 103, /* Scalar function Op French */
- OP_ENGLSH = 104, /* Scalar function Op English */
- OP_RAND = 105, /* Scalar function Op Rand(om) */
- OP_FIRST = 106, /* Index operator Find First */
- OP_NEXT = 107, /* Index operator Find Next */
- OP_SAME = 108, /* Index operator Find Next Same */
- OP_FSTDIF = 109, /* Index operator Find First dif */
- OP_NXTDIF = 110, /* Index operator Find Next dif */
- OP_VAL = 111, /* Scalar function Op Valist */
- OP_QUART = 112, /* Scalar function Op QUARTER */
- OP_CURDT = 113, /* Scalar function Op CurDate */
- OP_NWEEK = 114, /* Scalar function Op Week number*/
- OP_ROW = 115, /* Scalar function Op Row */
- OP_SYSTEM = 200, /* Scalar function Op System */
- OP_REMOVE = 201, /* Scalar function Op Remove */
- OP_RENAME = 202, /* Scalar function Op Rename */
- OP_FCOMP = 203}; /* Scalar function Op Compare */
-
-enum TUSE {USE_NO = 0, /* Table is not yet linearized */
- USE_LIN = 1, /* Table is linearized */
- USE_READY = 2, /* Column buffers are allocated */
- USE_OPEN = 3, /* Table is open */
- USE_CNT = 4, /* Specific to LNA */
- USE_NOKEY = 5}; /* Specific to SqlToHql */
-
-/***********************************************************************/
-/* Following definitions are used to indicate the status of a column. */
-/***********************************************************************/
-enum STATUS {BUF_NO = 0x00, /* Column buffer not allocated */
- BUF_EMPTY = 0x01, /* Column buffer is empty */
- BUF_READY = 0x02, /* Column buffer is ready */
- BUF_READ = 0x04, /* Column buffer has read value */
- BUF_MAPPED = 0x08}; /* Used by the VMPFAM class */
-
-/***********************************************************************/
-/* Following definitions are used to indicate how a column is used. */
-/* Corresponding bits are ON if the column is used in: */
-/***********************************************************************/
-enum COLUSE {U_P = 0x01, /* the projection list. */
- U_J_EXT = 0x02, /* a join filter. */
- U_J_INT = 0x04, /* a join after linearisation. */
-/*-- Such a column have a constant value throughout a subquery eval. --*/
- U_CORREL = 0x08, /* a correlated sub-query */
-/*-------------------- additional values used by CONNECT --------------*/
- 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_SPECIAL = 0x100, /* The column is special */
- U_UNSIGNED = 0x200, /* The column type is unsigned */
- U_ZEROFILL = 0x400}; /* The column is zero filled */
-
-/***********************************************************************/
-/* DB description class and block pointer definitions. */
-/***********************************************************************/
-typedef class XTAB *PTABLE;
-typedef class COLUMN *PCOLUMN;
-typedef class XOBJECT *PXOB;
-typedef class COLBLK *PCOL;
-typedef class TDB *PTDB;
-typedef class TDBASE *PTDBASE;
-typedef class TDBDOS *PTDBDOS;
-typedef class TDBFIX *PTDBFIX;
-typedef class TDBFMT *PTDBFMT;
-typedef class TDBCSV *PTDBCSV;
-typedef class TDBDOM *PTDBDOM;
-typedef class TDBDIR *PTDBDIR;
-typedef class DOSCOL *PDOSCOL;
-typedef class CSVCOL *PCSVCOL;
-typedef class MAPCOL *PMAPCOL;
-typedef class TDBMFT *PTDBMFT;
-typedef class TDBMCV *PTDBMCV;
-typedef class MCVCOL *PMCVCOL;
-typedef class RESCOL *PRESCOL;
-typedef class XXBASE *PKXBASE;
-typedef class KXYCOL *PXCOL;
-typedef class CATALOG *PCATLG;
-typedef class RELDEF *PRELDEF;
-typedef class TABDEF *PTABDEF;
-typedef class DOSDEF *PDOSDEF;
-typedef class CSVDEF *PCSVDEF;
-typedef class VCTDEF *PVCTDEF;
-typedef class PIVOTDEF *PPIVOTDEF;
-typedef class DOMDEF *PDOMDEF;
-typedef class DIRDEF *PDIRDEF;
-typedef class OEMDEF *POEMDEF;
-typedef class COLCRT *PCOLCRT;
-typedef class COLDEF *PCOLDEF;
-typedef class CONSTANT *PCONST;
-typedef class VALUE *PVAL;
-typedef class VALBLK *PVBLK;
-typedef class FILTER *PFIL;
-
-typedef struct _fblock *PFBLOCK;
-typedef struct _mblock *PMBLOCK;
-typedef struct _cblock *PCBLOCK;
-typedef struct _tabs *PTABS;
-typedef struct _qryres *PQRYRES;
-typedef struct _colres *PCOLRES;
-typedef struct _datpar *PDTP;
-typedef struct indx_used *PXUSED;
-
-/***********************************************************************/
-/* Utility blocks for file and storage. */
-/***********************************************************************/
-typedef struct _fblock { /* Opened (mapped) file block */
- struct _fblock *Next;
- LPCSTR Fname; /* Point on file name */
- size_t Length; /* File length (<4GB) */
- short Count; /* Nb of times map is used */
- short Type; /* TYPE_FB_FILE or TYPE_FB_MAP */
- MODE Mode; /* Open mode */
- char *Memory; /* Pointer to file mapping view */
- void *File; /* FILE pointer */
- HANDLE Handle; /* File handle */
- } FBLOCK;
-
-typedef struct _mblock { /* Memory block */
- PMBLOCK Next;
- bool Inlist; /* True if in mblock list */
- size_t Size; /* Size of allocation */
- bool Sub; /* True if suballocated */
- void *Memp; /* Memory pointer */
- } MBLOCK;
-
-/***********************************************************************/
-/* The QUERY application User Block. */
-/***********************************************************************/
-typedef struct { /* User application block */
- NAME Name; /* User application name */
- char Server[17]; /* Server name */
- char DBName[17]; /* Current database name */
- PCATLG Catalog; /* To CATALOG class */
- PQRYRES Result; /* To query result blocks */
- PFBLOCK Openlist; /* To file/map open list */
- PMBLOCK Memlist; /* To memory block list */
- PXUSED Xlist; /* To used index list */
- int Maxbmp; /* Maximum XDB2 bitmap size */
- int Check; /* General level of checking */
- int Numlines; /* Number of lines involved */
- USETEMP UseTemp; /* Use temporary file */
- int Vtdbno; /* Used for TDB number setting */
- bool Remote; /* true: if remotely called */
- bool Proginfo; /* true: return progress info */
- bool Subcor; /* Used for Progress info */
- size_t ProgMax; /* Used for Progress info */
- size_t ProgCur; /* Used for Progress info */
- size_t ProgSav; /* Used for Progress info */
- LPCSTR Step; /* Execution step name */
- } DBUSERBLK, *PDBUSER;
-
-/***********************************************************************/
-/* Column output format. */
-/***********************************************************************/
-typedef struct _format { /* Format descriptor block */
- char Type[2]; /* C:char, F:double, N:int, Dx: date */
- ushort Length; /* Output length */
- short Prec; /* Output precision */
- } FORMAT, *PFORMAT;
-
-/***********************************************************************/
-/* Definition of blocks used in type and copy routines. */
-/***********************************************************************/
-typedef struct _tabptr { /* start=P1 */
- struct _tabptr *Next;
- int Num; /* alignement */
- void *Old[50];
- void *New[50]; /* old and new values of copied ptrs */
- } TABPTR, *PTABPTR;
-
-typedef struct _tabadr { /* start=P3 */
- struct _tabadr *Next;
- int Num;
- void *Adx[50]; /* addr of pointers to be reset */
- } TABADR, *PTABADR;
-
-typedef struct _tabs {
- PGLOBAL G;
- PTABPTR P1;
- PTABADR P3;
- } TABS;
-
-/***********************************************************************/
-/* Argument of expression, function, filter etc. (Xobject) */
-/***********************************************************************/
-typedef struct _arg { /* Argument */
- PXOB To_Obj; /* To the argument object */
- PVAL Value; /* Argument value */
- bool Conv; /* TRUE if conversion is required */
- } ARGBLK, *PARG;
-
-typedef struct _oper { /* Operator */
- PSZ Name; /* The input/output operator name */
- OPVAL Val; /* Operator numeric value */
- int Mod; /* The modificator */
- } OPER, *POPER;
-
-/***********************************************************************/
-/* Following definitions are used to define table fields (columns). */
-/***********************************************************************/
-enum XFLD {FLD_NO = 0, /* Not a field definition item */
- FLD_NAME = 1, /* Item name */
- FLD_TYPE = 2, /* Field type */
- FLD_TYPENAME = 3, /* Field type name */
- FLD_PREC = 4, /* Field precision (length?) */
- FLD_LENGTH = 5, /* Field length (?) */
- FLD_SCALE = 6, /* Field scale (precision) */
- FLD_RADIX = 7, /* Field radix */
- FLD_NULL = 8, /* Field nullable property */
- FLD_REM = 9, /* Field comment (remark) */
- FLD_CHARSET = 10, /* Field collation */
- FLD_KEY = 11, /* Field key property */
- FLD_DEFAULT = 12, /* Field default value */
- FLD_EXTRA = 13, /* Field extra info */
- FLD_PRIV = 14, /* Field priviledges */
- FLD_DATEFMT = 15, /* Field date format */
- FLD_CAT = 16, /* Table catalog */
- FLD_SCHEM = 17, /* Table schema */
- FLD_TABNAME = 18}; /* Column Table name */
-
-/***********************************************************************/
-/* Result of last SQL noconv query. */
-/***********************************************************************/
-typedef struct _qryres {
- PCOLRES Colresp; /* Points to columns of result */
- bool Continued; /* true when more rows to fetch */
- bool Truncated; /* true when truncated by maxres */
- bool Suball; /* true when entirely suballocated */
- bool Info; /* true when info msg generated */
- int Maxsize; /* Max query number of lines */
- int Maxres; /* Allocation size */
- int Nblin; /* Number of rows in result set */
- int Nbcol; /* Number of columns in result set */
- int Cursor; /* Starting position to get data */
- int BadLines; /* Skipped bad lines in table file */
- } QRYRES, *PQRYRES;
-
-typedef struct _colres {
- PCOLRES Next; /* To next result column */
- PCOL Colp; /* To matching column block */
- PSZ Name; /* Column header */
- PVBLK Kdata; /* Column block of values */
- char *Nulls; /* Column null value array */
- int Type; /* Internal type */
- int Datasize; /* Overall data size */
- int Ncol; /* Column number */
- int Clen; /* Data individual internal size */
- int Length; /* Data individual print length */
- int Prec; /* Precision */
- int Flag; /* Flag option value */
- XFLD Fld; /* Type of field info */
- char Var; /* Type added information */
- } COLRES;
-
-#if defined(WIN32) && !defined(NOEX)
-#define DllExport __declspec( dllexport )
-#else // !WIN32
-#define DllExport
-#endif // !WIN32
-
-/***********************************************************************/
-/* Utility routines. */
-/***********************************************************************/
-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 AddPointer(PTABS, void *);
-PDTP MakeDateFormat(PGLOBAL, PSZ, bool, bool, int);
-int ExtractDate(char *, PDTP, int, int val[6]);
-
-/**************************************************************************/
-/* Allocate the result structure that will contain result data. */
-/**************************************************************************/
-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. */
-/***********************************************************************/
-DllExport FILE *PlugOpenFile(PGLOBAL, LPCSTR, LPCSTR);
-DllExport int PlugCloseFile(PGLOBAL, PFBLOCK, bool all = false);
-DllExport void PlugCleanup(PGLOBAL, bool);
-DllExport bool GetPromptAnswer(PGLOBAL, char *);
-DllExport char *GetAmName(PGLOBAL g, AMT am, void *memp = NULL);
-DllExport PDBUSER PlgMakeUser(PGLOBAL g);
-DllExport PDBUSER PlgGetUser(PGLOBAL g);
-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);
-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
-#define MSGID_OPEN_MODE_ERROR 2
-#define MSGID_OPEN_STRERROR 3
-#define MSGID_OPEN_ERROR_AND_STRERROR 4
-#define MSGID_OPEN_MODE_STRERROR 5
-#define MSGID_OPEN_EMPTY_FILE 6
-
-FILE *global_fopen(GLOBAL *g, int msgid, const char *path, const char *mode);
-int global_open(GLOBAL *g, int msgid, const char *filename, int flags);
-int global_open(GLOBAL *g, int msgid, const char *filename, int flags, int mode);
-DllExport LPCSTR PlugSetPath(LPSTR to, LPCSTR name, LPCSTR dir);
-char *MakeEscape(PGLOBAL g, char* str, char q);
-
-DllExport bool PushWarning(PGLOBAL, PTDBASE, int level = 1);
+/************** PlgDBSem H Declares Source Code File (.H) **************/
+/* Name: PLGDBSEM.H Version 3.6 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 1998-2014 */
+/* */
+/* This file contains the PlugDB++ application type definitions. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include required application header files */
+/***********************************************************************/
+#include "checklvl.h"
+
+/***********************************************************************/
+/* DB Constant definitions. */
+/***********************************************************************/
+#if defined(FRENCH)
+#define DEFAULT_LOCALE "French"
+#else // !FRENCH
+#define DEFAULT_LOCALE "English"
+#endif // !FRENCH
+
+#define DOS_MAX_PATH 144 /* Must be the same across systems */
+#define DOS_BUFF_LEN 100 /* Number of lines in binary file buffer */
+#undef DOMAIN /* For Unix version */
+
+enum BLKTYP {TYPE_TABLE = 50, /* Table Name/Srcdef/... Block */
+ TYPE_COLUMN = 51, /* Column Name/Qualifier Block */
+ TYPE_TDB = 53, /* Table Description Block */
+ TYPE_COLBLK = 54, /* Column Description Block */
+ TYPE_FILTER = 55, /* Filter Description Block */
+ TYPE_ARRAY = 63, /* General array type */
+ TYPE_PSZ = 64, /* Pointer to String ended by 0 */
+ TYPE_SQL = 65, /* Pointer to SQL block */
+ TYPE_XOBJECT = 69, /* Extended DB object */
+ TYPE_COLCRT = 71, /* Column creation block */
+ TYPE_CONST = 72, /* Constant */
+
+/*-------------------- type tokenized string --------------------------*/
+ TYPE_DATE = 8, /* Timestamp */
+/*-------------------- additional values used by LNA ------------------*/
+ TYPE_COLIST = 14, /* Column list */
+ TYPE_COL = 41, /* Column */
+/*-------------------- types used by scalar functions -----------------*/
+ TYPE_NUM = 12,
+ TYPE_UNDEF = 13,
+/*-------------------- file blocks used when closing ------------------*/
+ TYPE_FB_FILE = 22, /* File block (stream) */
+ TYPE_FB_MAP = 23, /* Mapped file block (storage) */
+ TYPE_FB_HANDLE = 24, /* File block (handle) */
+ TYPE_FB_XML = 21, /* DOM XML file block */
+ TYPE_FB_XML2 = 27}; /* libxml2 XML file block */
+
+enum TABTYPE {TAB_UNDEF = 0, /* Table of undefined type */
+ TAB_DOS = 1, /* Fixed column offset, variable LRECL */
+ TAB_FIX = 2, /* Fixed column offset, fixed LRECL */
+ TAB_BIN = 3, /* Like FIX but can have binary fields */
+ TAB_CSV = 4, /* DOS files with CSV records */
+ TAB_FMT = 5, /* DOS files with formatted recordss */
+ TAB_DBF = 6, /* DBF Dbase or Foxpro files */
+ TAB_XML = 7, /* XML or HTML files */
+ TAB_INI = 8, /* INI or CFG files */
+ TAB_VEC = 9, /* Vector column arrangement */
+ TAB_ODBC = 10, /* Table accessed via (unix)ODBC */
+ TAB_MYSQL = 11, /* MySQL table accessed via MySQL API */
+ TAB_DIR = 12, /* Returns a list of files */
+ TAB_MAC = 13, /* MAC address (Windows only) */
+ TAB_WMI = 14, /* WMI tables (Windows only) */
+ TAB_TBL = 15, /* Collection of CONNECT tables */
+ TAB_OEM = 16, /* OEM implemented table */
+ TAB_XCL = 17, /* XCL table */
+ TAB_OCCUR = 18, /* OCCUR table */
+ TAB_PRX = 19, /* Proxy (catalog) table */
+ TAB_PLG = 20, /* PLG NIY */
+ TAB_PIVOT = 21, /* PIVOT NIY */
+ TAB_JCT = 22, /* Junction tables NIY */
+ TAB_DMY = 23, /* DMY Dummy tables NIY */
+ TAB_NIY = 24}; /* Table not implemented yet */
+
+enum AMT {TYPE_AM_ERROR = 0, /* Type not defined */
+ TYPE_AM_ROWID = 1, /* ROWID type (special column) */
+ TYPE_AM_FILID = 2, /* FILEID type (special column) */
+ TYPE_AM_TAB = 3, /* Table (any type) */
+ TYPE_AM_VIEW = 4, /* VIEW (any type) */
+ TYPE_AM_SRVID = 5, /* SERVID type (special column) */
+ TYPE_AM_TABID = 6, /* TABID type (special column) */
+ TYPE_AM_CNSID = 7, /* CONSTID type (special column) */
+ TYPE_AM_COUNT = 10, /* CPT AM type no (count table) */
+ TYPE_AM_DCD = 20, /* Decode access method type no */
+ TYPE_AM_CMS = 30, /* CMS access method type no */
+ TYPE_AM_MAP = 32, /* MAP access method type no */
+ TYPE_AM_FMT = 33, /* DOS files with formatted recs */
+ TYPE_AM_CSV = 34, /* DOS files with CSV records */
+ TYPE_AM_MCV = 35, /* MAP files with CSV records */
+ TYPE_AM_DOS = 36, /* DOS am with Lrecl = V */
+ TYPE_AM_FIX = 38, /* DOS am with Lrecl = F */
+ TYPE_AM_BIN = 39, /* DOS am with Lrecl = B */
+ TYPE_AM_VCT = 40, /* VCT access method type no */
+ TYPE_AM_VMP = 43, /* VMP access method type no */
+ TYPE_AM_QRY = 50, /* QRY access method type no */
+ TYPE_AM_QRS = 51, /* QRYRES access method type no */
+ TYPE_AM_SQL = 60, /* SQL VIEW access method type */
+ TYPE_AM_PLG = 70, /* PLG access method type no */
+ TYPE_AM_PLM = 71, /* PDM access method type no */
+ TYPE_AM_DOM = 80, /* DOM access method type no */
+ TYPE_AM_DIR = 90, /* DIR access method type no */
+ TYPE_AM_ODBC = 100, /* ODBC access method type no */
+ TYPE_AM_XDBC = 101, /* XDBC access method type no */
+ TYPE_AM_OEM = 110, /* OEM access method type no */
+ TYPE_AM_TBL = 115, /* TBL access method type no */
+ TYPE_AM_PIVOT = 120, /* PIVOT access method type no */
+ TYPE_AM_SRC = 121, /* PIVOT multiple column type no */
+ TYPE_AM_FNC = 122, /* PIVOT source column type no */
+ TYPE_AM_XCOL = 124, /* XCOL access method type no */
+ TYPE_AM_XML = 127, /* XML access method type no */
+ TYPE_AM_OCCUR = 128, /* OCCUR access method type no */
+ TYPE_AM_PRX = 129, /* PROXY access method type no */
+ TYPE_AM_XTB = 130, /* SYS table access method type */
+ TYPE_AM_BLK = 131, /* BLK access method type no */
+ TYPE_AM_ZIP = 132, /* ZIP access method type no */
+ TYPE_AM_ZLIB = 133, /* ZLIB access method type no */
+ TYPE_AM_MAC = 137, /* MAC table access method type */
+ TYPE_AM_WMI = 139, /* WMI table access method type */
+ TYPE_AM_XCL = 140, /* SYS column access method type */
+ TYPE_AM_INI = 150, /* INI files access method */
+ TYPE_AM_TFC = 155, /* TFC (Circa) (Fuzzy compare) */
+ TYPE_AM_DBF = 160, /* DBF Dbase files am type no */
+ TYPE_AM_JCT = 170, /* Junction tables am type no */
+ TYPE_AM_DMY = 172, /* DMY Dummy tables am type no */
+ TYPE_AM_SET = 180, /* SET Set tables am type no */
+ TYPE_AM_MYSQL = 192, /* MYSQL access method type no */
+ TYPE_AM_MYX = 193, /* MYSQL EXEC access method type */
+ TYPE_AM_CAT = 195, /* Catalog access method type no */
+ TYPE_AM_OUT = 200}; /* Output relations (storage) */
+
+enum RECFM {RECFM_NAF = -2, /* Not a file */
+ RECFM_OEM = -1, /* OEM file access method */
+ RECFM_VAR = 0, /* Varying length DOS files */
+ RECFM_FIX = 1, /* Fixed length DOS files */
+ RECFM_BIN = 2, /* Binary DOS files (also fixed) */
+ RECFM_VCT = 3, /* VCT formatted files */
+ RECFM_ODBC = 4, /* Table accessed via ODBC */
+ RECFM_PLG = 5, /* Table accessed via PLGconn */
+ RECFM_DBF = 6}; /* DBase formatted file */
+
+enum MISC {DB_TABNO = 1, /* DB routines in Utility Table */
+ MAX_MULT_KEY = 10, /* Max multiple key number */
+ NAM_LEN = 128, /* Length of col and tab names */
+ ARRAY_SIZE = 50, /* Default array block size */
+// MAXRES = 500, /* Default maximum result lines */
+// MAXLIN = 10000, /* Default maximum data lines */
+ MAXBMP = 32}; /* Default XDB2 max bitmap size */
+
+#if 0
+enum ALGMOD {AMOD_AUTO = 0, /* PLG chooses best algorithm */
+ AMOD_SQL = 1, /* Use SQL algorithm */
+ AMOD_QRY = 2}; /* Use QUERY algorithm */
+#endif // 0
+
+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 */
+ MODE_INSERT = 40, /* Input/Output mode */
+ MODE_DELETE = 50, /* Input/Output mode */
+ MODE_ALTER = 60}; /* alter mode */
+
+#if !defined(RC_OK_DEFINED)
+#define RC_OK_DEFINED
+enum RCODE {RC_OK = 0, /* No error return code */
+ RC_NF = 1, /* Not found return code */
+ RC_EF = 2, /* End of file return code */
+ RC_FX = 3, /* Error return code */
+ RC_INFO = 4}; /* Success with info */
+#endif // !RC_OK_DEFINED
+
+enum OPVAL {OP_EQ = 1, /* Filtering operator = */
+ OP_NE = 2, /* Filtering operator != */
+ OP_GT = 3, /* Filtering operator > */
+ OP_GE = 4, /* Filtering operator >= */
+ OP_LT = 5, /* Filtering operator < */
+ OP_LE = 6, /* Filtering operator <= */
+ OP_IN = 7, /* Filtering operator IN */
+ OP_NULL = 8, /* Filtering operator IS NULL */
+ OP_EXIST = 9, /* Filtering operator EXISTS */
+ OP_LIKE = 10, /* Filtering operator LIKE */
+ OP_LOJ = -1, /* Filter op LEFT OUTER JOIN */
+ OP_ROJ = -2, /* Filter op RIGHT OUTER JOIN */
+ OP_DTJ = -3, /* Filter op DISTINCT JOIN */
+ OP_XX = 11, /* Filtering operator unknown */
+ OP_AND = 12, /* Filtering operator AND */
+ OP_OR = 13, /* Filtering operator OR */
+ OP_CNC = 14, /* Expression Concat operator */
+ OP_NOT = 15, /* Filtering operator NOT */
+ OP_SEP = 20, /* Filtering separator */
+ OP_ADD = 16, /* Expression Add operator */
+ OP_SUB = 17, /* Expression Substract operator */
+ OP_MULT = 18, /* Expression Multiply operator */
+ OP_DIV = 19, /* Expression Divide operator */
+ OP_NOP = 21, /* Scalar function is nopped */
+ OP_NUM = 22, /* Scalar function Op Num */
+ OP_ABS = 23, /* Scalar function Op Abs */
+ OP_MAX = 24, /* Scalar function Op Max */
+ OP_MIN = 25, /* Scalar function Op Min */
+ OP_CEIL = 26, /* Scalar function Op Ceil */
+ OP_FLOOR = 27, /* Scalar function Op Floor */
+ OP_MOD = 28, /* Scalar function Op Mod */
+ OP_ROUND = 29, /* Scalar function Op Round */
+ OP_SIGN = 30, /* Scalar function Op Sign */
+ OP_LEN = 31, /* Scalar function Op Len */
+ OP_INSTR = 32, /* Scalar function Op Instr */
+ OP_LEFT = 33, /* Scalar function Op Left */
+ OP_RIGHT = 34, /* Scalar function Op Right */
+ OP_ASCII = 35, /* Scalar function Op Ascii */
+ OP_EXP = 36, /* Scalar function Op Exp */
+ OP_LN = 37, /* Scalar function Op Ln */
+ OP_LOG = 38, /* Scalar function Op Log */
+ OP_POWER = 39, /* Scalar function Op Power */
+ OP_SQRT = 40, /* Scalar function Op Sqrt */
+ OP_COS = 41, /* Scalar function Op Cos */
+ OP_COSH = 42, /* Scalar function Op Cosh */
+ OP_SIN = 43, /* Scalar function Op Sin */
+ OP_SINH = 44, /* Scalar function Op Sinh */
+ OP_TAN = 45, /* Scalar function Op Tan */
+ OP_TANH = 46, /* Scalar function Op Tanh */
+ OP_USER = 47, /* Scalar function Op User */
+ OP_CHAR = 48, /* Scalar function Op Char */
+ OP_UPPER = 49, /* Scalar function Op Upper */
+ OP_LOWER = 50, /* Scalar function Op Lower */
+ OP_RPAD = 51, /* Scalar function Op Rpad */
+ OP_LPAD = 52, /* Scalar function Op Lpad */
+ OP_LTRIM = 53, /* Scalar function Op Ltrim */
+ OP_RTRIM = 54, /* Scalar function Op Rtrim */
+ OP_REPL = 55, /* Scalar function Op Replace */
+ OP_SUBST = 56, /* Scalar function Op Substr */
+ OP_LJUST = 57, /* Scalar function Op Ljustify */
+ OP_RJUST = 58, /* Scalar function Op Rjustify */
+ OP_CJUST = 59, /* Scalar function Op Cjustify */
+ OP_ENCODE = 60, /* Scalar function Op Encode */
+ OP_DECODE = 61, /* Scalar function Op Decode */
+ OP_SEQU = 62, /* Scalar function Op Sequence */
+ OP_IF = 63, /* Scalar function Op If */
+ OP_STRING = 64, /* Scalar function Op String */
+ OP_TOKEN = 65, /* Scalar function Op Token */
+ OP_SNDX = 66, /* Scalar function Op Soundex */
+ OP_DATE = 67, /* Scalar function Op Date */
+ OP_MDAY = 68, /* Scalar function Op Month Day */
+ OP_MONTH = 69, /* Scalar function Op Month of */
+ OP_YEAR = 70, /* Scalar function Op Year of */
+ OP_WDAY = 71, /* Scalar function Op Week Day */
+ OP_YDAY = 72, /* Scalar function Op Year Day */
+ OP_DBTWN = 73, /* Scalar function Op Days betwn */
+ OP_MBTWN = 74, /* Scalar function Op Months btw */
+ OP_YBTWN = 75, /* Scalar function Op Years btwn */
+ OP_ADDAY = 76, /* Scalar function Op Add Days */
+ OP_ADDMTH = 77, /* Scalar function Op Add Months */
+ OP_ADDYR = 78, /* Scalar function Op Add Years */
+ OP_NXTDAY = 79, /* Scalar function Op Next Day */
+ OP_SYSDT = 80, /* Scalar function Op SysDate */
+ OP_DELTA = 81, /* Scalar function Op Delta */
+ OP_LAST = 82, /* Scalar function Op Last */
+ OP_IFF = 83, /* Scalar function Op Iff */
+ OP_MAVG = 84, /* Scalar function Op Moving Avg */
+ OP_VWAP = 85, /* Scalar function Op VWAP */
+ OP_TIME = 86, /* Scalar function Op TIME */
+ OP_SETLEN = 87, /* Scalar function Op Set Length */
+ OP_TRANSL = 88, /* Scalar function Op Translate */
+ OP_BITAND = 89, /* Expression BitAnd operator */
+ OP_BITOR = 90, /* Expression BitOr operator */
+ OP_BITXOR = 91, /* Expression XOR operator */
+ OP_BITNOT = 92, /* Expression Complement operator*/
+ OP_CNTIN = 93, /* Scalar function Count In */
+ OP_FDISK = 94, /* Scalar function Disk of fileid*/
+ OP_FPATH = 95, /* Scalar function Path of fileid*/
+ OP_FNAME = 96, /* Scalar function Name of fileid*/
+ OP_FTYPE = 97, /* Scalar function Type of fileid*/
+ OP_XDATE = 98, /* Scalar function Op Fmt Date */
+ OP_SWITCH = 99, /* Scalar function Op Switch */
+ OP_EXIT = 100, /* Scalar function Op Exit */
+ OP_LIT = 101, /* Scalar function Op Literal */
+ OP_LOCALE = 102, /* Scalar function Op Locale */
+ OP_FRNCH = 103, /* Scalar function Op French */
+ OP_ENGLSH = 104, /* Scalar function Op English */
+ OP_RAND = 105, /* Scalar function Op Rand(om) */
+ OP_FIRST = 106, /* Index operator Find First */
+ OP_NEXT = 107, /* Index operator Find Next */
+ OP_SAME = 108, /* Index operator Find Next Same */
+ OP_FSTDIF = 109, /* Index operator Find First dif */
+ OP_NXTDIF = 110, /* Index operator Find Next dif */
+ OP_VAL = 111, /* Scalar function Op Valist */
+ OP_QUART = 112, /* Scalar function Op QUARTER */
+ OP_CURDT = 113, /* Scalar function Op CurDate */
+ OP_NWEEK = 114, /* Scalar function Op Week number*/
+ OP_ROW = 115, /* Scalar function Op Row */
+ OP_PREV = 116, /* Index operator Find Previous */
+ OP_SYSTEM = 200, /* Scalar function Op System */
+ OP_REMOVE = 201, /* Scalar function Op Remove */
+ OP_RENAME = 202, /* Scalar function Op Rename */
+ OP_FCOMP = 203}; /* Scalar function Op Compare */
+
+enum TUSE {USE_NO = 0, /* Table is not yet linearized */
+ USE_LIN = 1, /* Table is linearized */
+ USE_READY = 2, /* Column buffers are allocated */
+ USE_OPEN = 3, /* Table is open */
+ USE_CNT = 4, /* Specific to LNA */
+ USE_NOKEY = 5}; /* Specific to SqlToHql */
+
+/***********************************************************************/
+/* Following definitions are used to indicate the status of a column. */
+/***********************************************************************/
+enum STATUS {BUF_NO = 0x00, /* Column buffer not allocated */
+ BUF_EMPTY = 0x01, /* Column buffer is empty */
+ BUF_READY = 0x02, /* Column buffer is ready */
+ BUF_READ = 0x04, /* Column buffer has read value */
+ BUF_MAPPED = 0x08}; /* Used by the VMPFAM class */
+
+/***********************************************************************/
+/* Following definitions are used to indicate how a column is used. */
+/* Corresponding bits are ON if the column is used in: */
+/***********************************************************************/
+enum COLUSE {U_P = 0x01, /* the projection list. */
+ U_J_EXT = 0x02, /* a join filter. */
+ U_J_INT = 0x04, /* a join after linearisation. */
+/*-- Such a column have a constant value throughout a subquery eval. --*/
+ U_CORREL = 0x08, /* a correlated sub-query */
+/*-------------------- additional values used by CONNECT --------------*/
+ 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_SPECIAL = 0x100, /* The column is special */
+ U_UNSIGNED = 0x200, /* The column type is unsigned */
+ U_ZEROFILL = 0x400}; /* The column is zero filled */
+
+/***********************************************************************/
+/* DB description class and block pointer definitions. */
+/***********************************************************************/
+typedef class XTAB *PTABLE;
+typedef class COLUMN *PCOLUMN;
+typedef class XOBJECT *PXOB;
+typedef class COLBLK *PCOL;
+typedef class TDB *PTDB;
+typedef class TDBASE *PTDBASE;
+typedef class TDBDOS *PTDBDOS;
+typedef class TDBFIX *PTDBFIX;
+typedef class TDBFMT *PTDBFMT;
+typedef class TDBCSV *PTDBCSV;
+typedef class TDBDOM *PTDBDOM;
+typedef class TDBDIR *PTDBDIR;
+typedef class DOSCOL *PDOSCOL;
+typedef class CSVCOL *PCSVCOL;
+typedef class MAPCOL *PMAPCOL;
+typedef class TDBMFT *PTDBMFT;
+typedef class TDBMCV *PTDBMCV;
+typedef class MCVCOL *PMCVCOL;
+typedef class RESCOL *PRESCOL;
+typedef class XXBASE *PKXBASE;
+typedef class KXYCOL *PXCOL;
+typedef class CATALOG *PCATLG;
+typedef class RELDEF *PRELDEF;
+typedef class TABDEF *PTABDEF;
+typedef class DOSDEF *PDOSDEF;
+typedef class CSVDEF *PCSVDEF;
+typedef class VCTDEF *PVCTDEF;
+typedef class PIVOTDEF *PPIVOTDEF;
+typedef class DOMDEF *PDOMDEF;
+typedef class DIRDEF *PDIRDEF;
+typedef class OEMDEF *POEMDEF;
+typedef class COLCRT *PCOLCRT;
+typedef class COLDEF *PCOLDEF;
+typedef class CONSTANT *PCONST;
+typedef class VALUE *PVAL;
+typedef class VALBLK *PVBLK;
+typedef class FILTER *PFIL;
+
+typedef struct _fblock *PFBLOCK;
+typedef struct _mblock *PMBLOCK;
+typedef struct _cblock *PCBLOCK;
+typedef struct _tabs *PTABS;
+typedef struct _qryres *PQRYRES;
+typedef struct _colres *PCOLRES;
+typedef struct _datpar *PDTP;
+typedef struct indx_used *PXUSED;
+
+/***********************************************************************/
+/* Utility blocks for file and storage. */
+/***********************************************************************/
+typedef struct _fblock { /* Opened (mapped) file block */
+ struct _fblock *Next;
+ LPCSTR Fname; /* Point on file name */
+ size_t Length; /* File length (<4GB) */
+ short Count; /* Nb of times map is used */
+ short Type; /* TYPE_FB_FILE or TYPE_FB_MAP */
+ MODE Mode; /* Open mode */
+ char *Memory; /* Pointer to file mapping view */
+ void *File; /* FILE pointer */
+ HANDLE Handle; /* File handle */
+ } FBLOCK;
+
+typedef struct _mblock { /* Memory block */
+ PMBLOCK Next;
+ bool Inlist; /* True if in mblock list */
+ size_t Size; /* Size of allocation */
+ bool Sub; /* True if suballocated */
+ void *Memp; /* Memory pointer */
+ } MBLOCK;
+
+/***********************************************************************/
+/* The QUERY application User Block. */
+/***********************************************************************/
+typedef struct { /* User application block */
+ NAME Name; /* User application name */
+ char Server[17]; /* Server name */
+ char DBName[17]; /* Current database name */
+ PCATLG Catalog; /* To CATALOG class */
+ PQRYRES Result; /* To query result blocks */
+ PFBLOCK Openlist; /* To file/map open list */
+ PMBLOCK Memlist; /* To memory block list */
+ PXUSED Xlist; /* To used index list */
+ int Maxbmp; /* Maximum XDB2 bitmap size */
+ int Check; /* General level of checking */
+ int Numlines; /* Number of lines involved */
+ USETEMP UseTemp; /* Use temporary file */
+ int Vtdbno; /* Used for TDB number setting */
+ bool Remote; /* true: if remotely called */
+ bool Proginfo; /* true: return progress info */
+ bool Subcor; /* Used for Progress info */
+ size_t ProgMax; /* Used for Progress info */
+ size_t ProgCur; /* Used for Progress info */
+ size_t ProgSav; /* Used for Progress info */
+ LPCSTR Step; /* Execution step name */
+ } DBUSERBLK, *PDBUSER;
+
+/***********************************************************************/
+/* Column output format. */
+/***********************************************************************/
+typedef struct _format { /* Format descriptor block */
+ char Type[2]; /* C:char, F:double, N:int, Dx: date */
+ ushort Length; /* Output length */
+ short Prec; /* Output precision */
+ } FORMAT, *PFORMAT;
+
+/***********************************************************************/
+/* Definition of blocks used in type and copy routines. */
+/***********************************************************************/
+typedef struct _tabptr { /* start=P1 */
+ struct _tabptr *Next;
+ int Num; /* alignement */
+ void *Old[50];
+ void *New[50]; /* old and new values of copied ptrs */
+ } TABPTR, *PTABPTR;
+
+typedef struct _tabadr { /* start=P3 */
+ struct _tabadr *Next;
+ int Num;
+ void *Adx[50]; /* addr of pointers to be reset */
+ } TABADR, *PTABADR;
+
+typedef struct _tabs {
+ PGLOBAL G;
+ PTABPTR P1;
+ PTABADR P3;
+ } TABS;
+
+/***********************************************************************/
+/* Argument of expression, function, filter etc. (Xobject) */
+/***********************************************************************/
+typedef struct _arg { /* Argument */
+ PXOB To_Obj; /* To the argument object */
+ PVAL Value; /* Argument value */
+ bool Conv; /* TRUE if conversion is required */
+ } ARGBLK, *PARG;
+
+typedef struct _oper { /* Operator */
+ PSZ Name; /* The input/output operator name */
+ OPVAL Val; /* Operator numeric value */
+ int Mod; /* The modificator */
+ } OPER, *POPER;
+
+/***********************************************************************/
+/* Following definitions are used to define table fields (columns). */
+/***********************************************************************/
+enum XFLD {FLD_NO = 0, /* Not a field definition item */
+ FLD_NAME = 1, /* Item name */
+ FLD_TYPE = 2, /* Field type */
+ FLD_TYPENAME = 3, /* Field type name */
+ FLD_PREC = 4, /* Field precision (length?) */
+ FLD_LENGTH = 5, /* Field length (?) */
+ FLD_SCALE = 6, /* Field scale (precision) */
+ FLD_RADIX = 7, /* Field radix */
+ FLD_NULL = 8, /* Field nullable property */
+ FLD_REM = 9, /* Field comment (remark) */
+ FLD_CHARSET = 10, /* Field collation */
+ FLD_KEY = 11, /* Field key property */
+ FLD_DEFAULT = 12, /* Field default value */
+ FLD_EXTRA = 13, /* Field extra info */
+ FLD_PRIV = 14, /* Field priviledges */
+ FLD_DATEFMT = 15, /* Field date format */
+ FLD_CAT = 16, /* Table catalog */
+ FLD_SCHEM = 17, /* Table schema */
+ FLD_TABNAME = 18}; /* Column Table name */
+
+/***********************************************************************/
+/* Result of last SQL noconv query. */
+/***********************************************************************/
+typedef struct _qryres {
+ PCOLRES Colresp; /* Points to columns of result */
+ bool Continued; /* true when more rows to fetch */
+ bool Truncated; /* true when truncated by maxres */
+ bool Suball; /* true when entirely suballocated */
+ bool Info; /* true when info msg generated */
+ int Maxsize; /* Max query number of lines */
+ int Maxres; /* Allocation size */
+ int Nblin; /* Number of rows in result set */
+ int Nbcol; /* Number of columns in result set */
+ int Cursor; /* Starting position to get data */
+ int BadLines; /* Skipped bad lines in table file */
+ } QRYRES, *PQRYRES;
+
+typedef struct _colres {
+ PCOLRES Next; /* To next result column */
+ PCOL Colp; /* To matching column block */
+ PSZ Name; /* Column header */
+ PVBLK Kdata; /* Column block of values */
+ char *Nulls; /* Column null value array */
+ int Type; /* Internal type */
+ int Datasize; /* Overall data size */
+ int Ncol; /* Column number */
+ int Clen; /* Data individual internal size */
+ int Length; /* Data individual print length */
+ int Prec; /* Precision */
+ int Flag; /* Flag option value */
+ XFLD Fld; /* Type of field info */
+ char Var; /* Type added information */
+ } COLRES;
+
+#if defined(WIN32) && !defined(NOEX)
+#define DllExport __declspec( dllexport )
+#else // !WIN32
+#define DllExport
+#endif // !WIN32
+
+/***********************************************************************/
+/* Utility routines. */
+/***********************************************************************/
+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 AddPointer(PTABS, void *);
+PDTP MakeDateFormat(PGLOBAL, PSZ, bool, bool, int);
+int ExtractDate(char *, PDTP, int, int val[6]);
+
+/**************************************************************************/
+/* Allocate the result structure that will contain result data. */
+/**************************************************************************/
+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. */
+/***********************************************************************/
+DllExport FILE *PlugOpenFile(PGLOBAL, LPCSTR, LPCSTR);
+DllExport int PlugCloseFile(PGLOBAL, PFBLOCK, bool all = false);
+DllExport void PlugCleanup(PGLOBAL, bool);
+DllExport bool GetPromptAnswer(PGLOBAL, char *);
+DllExport char *GetAmName(PGLOBAL g, AMT am, void *memp = NULL);
+DllExport PDBUSER PlgMakeUser(PGLOBAL g);
+DllExport PDBUSER PlgGetUser(PGLOBAL g);
+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);
+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
+#define MSGID_OPEN_MODE_ERROR 2
+#define MSGID_OPEN_STRERROR 3
+#define MSGID_OPEN_ERROR_AND_STRERROR 4
+#define MSGID_OPEN_MODE_STRERROR 5
+#define MSGID_OPEN_EMPTY_FILE 6
+
+FILE *global_fopen(GLOBAL *g, int msgid, const char *path, const char *mode);
+int global_open(GLOBAL *g, int msgid, const char *filename, int flags);
+int global_open(GLOBAL *g, int msgid, const char *filename, int flags, int mode);
+DllExport LPCSTR PlugSetPath(LPSTR to, LPCSTR name, LPCSTR dir);
+char *MakeEscape(PGLOBAL g, char* str, char q);
+
+DllExport bool PushWarning(PGLOBAL, PTDBASE, int level = 1);
diff --git a/storage/connect/plugutil.c b/storage/connect/plugutil.c
index 627861c1c36..c3b77544983 100644
--- a/storage/connect/plugutil.c
+++ b/storage/connect/plugutil.c
@@ -115,11 +115,6 @@ void htrc(char const *fmt, ...)
va_list ap;
va_start (ap, fmt);
-//if (trace == 0 || (trace == 1 && !debug) || !fmt) {
-// printf("In %s wrong trace=%d debug=%p fmt=%p\n",
-// __FILE__, trace, debug, fmt);
-// trace = 0;
-// } // endif trace
//if (trace == 1)
// vfprintf(debug, fmt, ap);
@@ -256,7 +251,20 @@ LPCSTR PlugSetPath(LPSTR pBuff, LPCSTR prefix, LPCSTR FileName, LPCSTR defpath)
strcpy(pBuff, FileName); // FileName includes absolute path
return pBuff;
} // endif
-
+
+#if !defined(WIN32)
+ if (*FileName == '~') {
+ if (_fullpath(pBuff, FileName, _MAX_PATH)) {
+ if (trace > 1)
+ htrc("pbuff='%s'\n", pBuff);
+
+ return pBuff;
+ } else
+ return FileName; // Error, return unchanged name
+
+ } // endif FileName
+#endif // !WIN32
+
if (strcmp(prefix, ".") && !PlugIsAbsolutePath(defpath))
{
char tmp[_MAX_PATH];
@@ -478,10 +486,9 @@ void *PlugSubAlloc(PGLOBAL g, void *memp, size_t size)
size = ((size + 7) / 8) * 8; /* Round up size to multiple of 8 */
pph = (PPOOLHEADER)memp;
-#if defined(DEBUG2) || defined(DEBUG3)
- htrc("SubAlloc in %p size=%d used=%d free=%d\n",
- memp, size, pph->To_Free, pph->FreeBlk);
-#endif
+ if (trace > 2)
+ htrc("SubAlloc in %p size=%d used=%d free=%d\n",
+ memp, size, pph->To_Free, pph->FreeBlk);
if ((uint)size > pph->FreeBlk) { /* Not enough memory left in pool */
char *pname = "Work";
@@ -490,9 +497,8 @@ void *PlugSubAlloc(PGLOBAL g, void *memp, size_t size)
"Not enough memory in %s area for request of %u (used=%d free=%d)",
pname, (uint) size, pph->To_Free, pph->FreeBlk);
-#if defined(DEBUG2) || defined(DEBUG3)
- htrc("%s\n", g->Message);
-#endif
+ if (trace)
+ htrc("PlugSubAlloc: %s\n", g->Message);
longjmp(g->jumper[g->jump_level], 1);
} /* endif size OS32 code */
@@ -503,10 +509,11 @@ void *PlugSubAlloc(PGLOBAL g, void *memp, size_t size)
memp = MakePtr(memp, pph->To_Free); /* Points to suballocated block */
pph->To_Free += size; /* New offset of pool free block */
pph->FreeBlk -= size; /* New size of pool free block */
-#if defined(DEBUG2) || defined(DEBUG3)
- htrc("Done memp=%p used=%d free=%d\n",
- memp, pph->To_Free, pph->FreeBlk);
-#endif
+
+ if (trace > 2)
+ htrc("Done memp=%p used=%d free=%d\n",
+ memp, pph->To_Free, pph->FreeBlk);
+
return (memp);
} /* end of PlugSubAlloc */
diff --git a/storage/connect/tabmysql.cpp b/storage/connect/tabmysql.cpp
index 2556051249c..5029b7539f9 100644
--- a/storage/connect/tabmysql.cpp
+++ b/storage/connect/tabmysql.cpp
@@ -1134,10 +1134,13 @@ MYSQLCOL::MYSQLCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am)
MYSQLCOL::MYSQLCOL(MYSQL_FIELD *fld, PTDB tdbp, int i, PSZ am)
: COLBLK(NULL, tdbp, i)
{
+ const char *chset = get_charset_name(fld->charsetnr);
+ char v = (!strcmp(chset, "binary")) ? 'B' : 0;
+
Name = fld->name;
Opt = 0;
Precision = Long = fld->length;
- Buf_Type = MYSQLtoPLG(fld->type);
+ Buf_Type = MYSQLtoPLG(fld->type, &v);
strcpy(Format.Type, GetFormatType(Buf_Type));
Format.Length = Long;
Format.Prec = fld->decimals;
@@ -1616,5 +1619,5 @@ TDBMCL::TDBMCL(PMYDEF tdp) : TDBCAT(tdp)
/***********************************************************************/
PQRYRES TDBMCL::GetResult(PGLOBAL g)
{
- return MyColumns(g, Host, Db, User, Pwd, Tab, NULL, Port, false);
+ return MyColumns(g, NULL, Host, Db, User, Pwd, Tab, NULL, Port, false);
} // end of GetResult
diff --git a/storage/connect/tabpivot.cpp b/storage/connect/tabpivot.cpp
index 7cde2ab4cbd..b236d3c62cd 100644
--- a/storage/connect/tabpivot.cpp
+++ b/storage/connect/tabpivot.cpp
@@ -96,10 +96,21 @@ PIVAID::PIVAID(const char *tab, const char *src, const char *picol,
PQRYRES PIVAID::MakePivotColumns(PGLOBAL g)
{
char *query, *colname, buf[64];
- int ndif, nblin, w = 0;
+ int rc, ndif, nblin, w = 0;
+ bool b = false;
PVAL valp;
PCOLRES *pcrp, crp, fncrp = NULL;
+ // Save stack and allocation environment and prepare error return
+ if (g->jump_level == MAX_JUMP) {
+ strcpy(g->Message, MSG(TOO_MANY_JUMPS));
+ return NULL;
+ } // endif jump_level
+
+ if ((rc= setjmp(g->jumper[++g->jump_level])) != 0) {
+ goto err;
+ } // endif rc
+
if (!Tabsrc && Tabname) {
// Locate the query
query = (char*)PlugSubAlloc(g, NULL, strlen(Tabname) + 16);
@@ -113,16 +124,17 @@ PQRYRES PIVAID::MakePivotColumns(PGLOBAL g)
// Open a MySQL connection for this table
if (Myc.Open(g, Host, Database, User, Pwd, Port))
return NULL;
+ else
+ b = true;
// Send the source command to MySQL
- if (Myc.ExecSQL(g, query, &w) == RC_FX) {
- Myc.Close();
- return NULL;
- } // endif Exec
+ if (Myc.ExecSQL(g, query, &w) == RC_FX)
+ goto err;
// We must have a storage query to get pivot column values
Qryp = Myc.GetResult(g, true);
Myc.Close();
+ b = false;
if (!Fncol) {
for (crp = Qryp->Colresp; crp; crp = crp->Next)
@@ -152,6 +164,11 @@ PQRYRES PIVAID::MakePivotColumns(PGLOBAL g)
// Prepare the column list
for (pcrp = &Qryp->Colresp; crp = *pcrp; )
if (!stricmp(Picol, crp->Name)) {
+ if (crp->Nulls) {
+ sprintf(g->Message, "Pivot column %s cannot be nullable", Picol);
+ return NULL;
+ } // endif Nulls
+
Rblkp = crp->Kdata;
*pcrp = crp->Next;
} else if (!stricmp(Fncol, crp->Name)) {
@@ -218,6 +235,12 @@ PQRYRES PIVAID::MakePivotColumns(PGLOBAL g)
// We added ndif columns and removed 2 (picol and fncol)
Qryp->Nbcol += (ndif - 2);
return Qryp;
+
+err:
+ if (b)
+ Myc.Close();
+
+ return NULL;
} // end of MakePivotColumns
/***********************************************************************/
diff --git a/storage/connect/tabutil.cpp b/storage/connect/tabutil.cpp
index 6d83852ccb8..e77af35a8a4 100644
--- a/storage/connect/tabutil.cpp
+++ b/storage/connect/tabutil.cpp
@@ -55,6 +55,7 @@
#include "ha_connect.h"
extern "C" int trace;
+extern "C" int zconv;
/************************************************************************/
/* Used by MYSQL tables to get MySQL parameters from the calling proxy */
@@ -129,7 +130,7 @@ PQRYRES TabColumns(PGLOBAL g, THD *thd, const char *db,
FLD_LENGTH, FLD_SCALE, FLD_RADIX, FLD_NULL,
FLD_REM, FLD_NO, FLD_CHARSET};
unsigned int length[] = {0, 4, 16, 4, 4, 4, 4, 4, 0, 32, 32};
- char *fld, *fmt, v;
+ char *fld, *colname, *chset, *fmt, v;
int i, n, ncol = sizeof(buftyp) / sizeof(int);
int prec, len, type, scale;
bool mysql;
@@ -176,21 +177,37 @@ PQRYRES TabColumns(PGLOBAL g, THD *thd, const char *db,
/**********************************************************************/
/* Now get the results into blocks. */
/**********************************************************************/
- for (i = 0, field= s->field; *field; i++, field++) {
+ for (i = 0, field= s->field; *field; field++) {
fp= *field;
// Get column name
crp = qrp->Colresp; // Column_Name
- fld = (char *)fp->field_name;
- crp->Kdata->SetValue(fld, i);
- v = 0;
+ colname = (char *)fp->field_name;
+ crp->Kdata->SetValue(colname, i);
+
+ chset = (char *)fp->charset()->name;
+ v = (!strcmp(chset, "binary")) ? 'B' : 0;
if ((type = MYSQLtoPLG(fp->type(), &v)) == TYPE_ERROR) {
- sprintf(g->Message, "Unsupported column type %s", GetTypeName(type));
+ if (v == 'K') {
+ // Skip this column
+ sprintf(g->Message, "Column %s skipped (unsupported type)", colname);
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
+ continue;
+ } // endif v
+
+ sprintf(g->Message, "Column %s unsupported type", colname);
qrp = NULL;
break;
} // endif type
+ if (v == 'X') {
+ len = zconv;
+ sprintf(g->Message, "Column %s converted to varchar(%d)",
+ colname, len);
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
+ } // endif v
+
crp = crp->Next; // Data_Type
crp->Kdata->SetValue(type, i);
@@ -198,11 +215,12 @@ PQRYRES TabColumns(PGLOBAL g, THD *thd, const char *db,
crp->Nulls[i] = 'Z';
else if (fp->flags & UNSIGNED_FLAG)
crp->Nulls[i] = 'U';
- else
- crp->Nulls[i] = v;
+ else // X means TEXT field
+ crp->Nulls[i] = (v == 'X') ? 'V' : v;
crp = crp->Next; // Type_Name
crp->Kdata->SetValue(GetTypeName(type), i);
+ fmt = NULL;
if (type == TYPE_DATE) {
// When creating tables we do need info about date columns
@@ -214,7 +232,7 @@ PQRYRES TabColumns(PGLOBAL g, THD *thd, const char *db,
prec = len = fp->field_length;
} // endif mysql
- } else {
+ } else if (v != 'X') {
if (type == TYPE_DECIM)
prec = ((Field_new_decimal*)fp)->precision;
else
@@ -222,8 +240,8 @@ PQRYRES TabColumns(PGLOBAL g, THD *thd, const char *db,
// prec = (prec(???) == NOT_FIXED_DEC) ? 0 : fp->field_length;
len = fp->char_length();
- fmt = NULL;
- } // endif type
+ } else
+ prec = len = zconv;
crp = crp->Next; // Precision
crp->Kdata->SetValue(prec, i);
@@ -259,6 +277,7 @@ PQRYRES TabColumns(PGLOBAL g, THD *thd, const char *db,
// Add this item
qrp->Nblin++;
+ i++; // Can be skipped
} // endfor field
/**********************************************************************/
diff --git a/storage/connect/user_connect.cc b/storage/connect/user_connect.cc
index e170352874f..b5f835c9cc9 100644
--- a/storage/connect/user_connect.cc
+++ b/storage/connect/user_connect.cc
@@ -48,6 +48,7 @@
#include "mycat.h"
extern "C" int trace;
+extern uint worksize;
/****************************************************************************/
/* Initialize the user_connect static member. */
@@ -94,8 +95,9 @@ bool user_connect::user_init()
PDBUSER dup= NULL;
// Areasize= 64M because of VEC tables. Should be parameterisable
- g= PlugInit(NULL, 67108864);
+//g= PlugInit(NULL, 67108864);
//g= PlugInit(NULL, 134217728); // 128M was because of old embedded tests
+ g= PlugInit(NULL, worksize);
// Check whether the initialization is complete
if (!g || !g->Sarea || PlugSubSet(g, g->Sarea, g->Sarea_Size)
@@ -142,6 +144,20 @@ bool user_connect::CheckCleanup(void)
{
if (thdp->query_id > last_query_id) {
PlugCleanup(g, true);
+
+ if (g->Sarea_Size != worksize) {
+ if (g->Sarea)
+ free(g->Sarea);
+
+ // Check whether the work area size was changed
+ if (!(g->Sarea = PlugAllocMem(g, worksize))) {
+ g->Sarea = PlugAllocMem(g, g->Sarea_Size);
+ worksize = g->Sarea_Size; // Was too big
+ } else
+ g->Sarea_Size = worksize; // Ok
+
+ } // endif worksize
+
PlugSubSet(g, g->Sarea, g->Sarea_Size);
g->Xchk = NULL;
g->Createas = 0;
diff --git a/storage/connect/valblk.cpp b/storage/connect/valblk.cpp
index 893e8b1de81..c0fa37aab6e 100644
--- a/storage/connect/valblk.cpp
+++ b/storage/connect/valblk.cpp
@@ -44,6 +44,7 @@
#define CheckParms(V, N) ChkIndx(N); ChkTyp(V);
extern "C" int trace;
+extern MBLOCK Nmblk; /* Used to initialize MBLOCK's */
/***********************************************************************/
/* AllocValBlock: allocate a VALBLK according to type. */
@@ -105,8 +106,7 @@ PVBLK AllocValBlock(PGLOBAL g, void *mp, int type, int nval, int len,
return NULL;
} // endswitch Type
- blkp->Init(g, check);
- return blkp;
+ return (blkp->Init(g, check)) ? NULL : blkp;
} // end of AllocValBlock
/* -------------------------- Class VALBLK --------------------------- */
@@ -116,6 +116,7 @@ PVBLK AllocValBlock(PGLOBAL g, void *mp, int type, int nval, int len,
/***********************************************************************/
VALBLK::VALBLK(void *mp, int type, int nval, bool un)
{
+ Mblk = Nmblk;
Blkp = mp;
To_Nulls = NULL;
Check = true;
@@ -180,6 +181,22 @@ void VALBLK::SetNullable(bool b)
} // end of SetNullable
/***********************************************************************/
+/* Buffer allocation routine. */
+/***********************************************************************/
+bool VALBLK::AllocBuff(PGLOBAL g, size_t size)
+ {
+ Mblk.Size = size;
+
+ if (!(Blkp = PlgDBalloc(g, NULL, Mblk))) {
+ sprintf(g->Message, MSG(MEM_ALLOC_ERR), "Blkp", Mblk.Size);
+ fprintf(stderr, "%s\n", g->Message);
+ return true;
+ } // endif Blkp
+
+ return false;
+ } // end of AllocBuff
+
+/***********************************************************************/
/* Check functions. */
/***********************************************************************/
void VALBLK::ChkIndx(int n)
@@ -229,13 +246,15 @@ TYPBLK<TYPE>::TYPBLK(void *mp, int nval, int type, int prec, bool un)
/* Initialization routine. */
/***********************************************************************/
template <class TYPE>
-void TYPBLK<TYPE>::Init(PGLOBAL g, bool check)
+bool TYPBLK<TYPE>::Init(PGLOBAL g, bool check)
{
if (!Blkp)
- Blkp = PlugSubAlloc(g, NULL, Nval * sizeof(TYPE));
+ if (AllocBuff(g, Nval * sizeof(TYPE)))
+ return true;
Check = check;
Global = g;
+ return false;
} // end of Init
/***********************************************************************/
@@ -606,16 +625,18 @@ CHRBLK::CHRBLK(void *mp, int nval, int len, int prec, bool blank)
/***********************************************************************/
/* Initialization routine. */
/***********************************************************************/
-void CHRBLK::Init(PGLOBAL g, bool check)
+bool CHRBLK::Init(PGLOBAL g, bool check)
{
Valp = (char*)PlugSubAlloc(g, NULL, Long + 1);
Valp[Long] = '\0';
if (!Blkp)
- Blkp = PlugSubAlloc(g, NULL, Nval * Long);
+ if (AllocBuff(g, Nval * Long))
+ return true;
Check = check;
Global = g;
+ return false;
} // end of Init
/***********************************************************************/
@@ -996,13 +1017,15 @@ STRBLK::STRBLK(PGLOBAL g, void *mp, int nval)
/***********************************************************************/
/* Initialization routine. */
/***********************************************************************/
-void STRBLK::Init(PGLOBAL g, bool check)
+bool STRBLK::Init(PGLOBAL g, bool check)
{
if (!Blkp)
- Blkp = PlugSubAlloc(g, NULL, Nval * sizeof(PSZ));
+ if (AllocBuff(g, Nval * sizeof(PSZ)))
+ return true;
Check = check;
Global = g;
+ return false;
} // end of Init
/***********************************************************************/
diff --git a/storage/connect/valblk.h b/storage/connect/valblk.h
index f85d34d6b77..3ff34c4bcdf 100644
--- a/storage/connect/valblk.h
+++ b/storage/connect/valblk.h
@@ -1,27 +1,27 @@
-/*************** Valblk H Declares Source Code File (.H) ***************/
-/* Name: VALBLK.H Version 2.1 */
-/* */
-/* (C) Copyright to the author Olivier BERTRAND 2005-2014 */
-/* */
-/* This file contains the VALBLK and derived classes declares. */
-/***********************************************************************/
-
-/***********************************************************************/
-/* Include required application header files */
-/* assert.h is header required when using the assert function. */
-/* block.h is header containing Block global declarations. */
-/***********************************************************************/
-#ifndef __VALBLK__H__
-#define __VALBLK__H__
-#include "value.h"
-
-/***********************************************************************/
-/* Utility used to allocate value blocks. */
-/***********************************************************************/
-DllExport PVBLK AllocValBlock(PGLOBAL, void*, int, int, int, int,
- bool, bool, bool);
-const char *GetFmt(int type, bool un = false);
-
+/*************** Valblk H Declares Source Code File (.H) ***************/
+/* Name: VALBLK.H Version 2.1 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2005-2014 */
+/* */
+/* This file contains the VALBLK and derived classes declares. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include required application header files */
+/* assert.h is header required when using the assert function. */
+/* block.h is header containing Block global declarations. */
+/***********************************************************************/
+#ifndef __VALBLK__H__
+#define __VALBLK__H__
+#include "value.h"
+
+/***********************************************************************/
+/* Utility used to allocate value blocks. */
+/***********************************************************************/
+DllExport PVBLK AllocValBlock(PGLOBAL, void*, int, int, int, int,
+ bool, bool, bool);
+const char *GetFmt(int type, bool un = false);
+
/***********************************************************************/
/* DB static external variables. */
/***********************************************************************/
@@ -52,280 +52,282 @@ class MBVALS : public BLOCK {
typedef class MBVALS *PMBV;
-/***********************************************************************/
-/* Class VALBLK represent a base class for variable blocks. */
-/***********************************************************************/
-class VALBLK : public BLOCK {
- public:
- // Constructors
- VALBLK(void *mp, int type, int nval, bool un = false);
-
- // Implementation
- int GetNval(void) {return Nval;}
- void SetNval(int n) {Nval = n;}
- void *GetValPointer(void) {return Blkp;}
- void SetValPointer(void *mp) {Blkp = mp;}
- int GetType(void) {return Type;}
- int GetPrec(void) {return Prec;}
- void SetCheck(bool b) {Check = b;}
- void MoveNull(int i, int j)
- {if (To_Nulls) To_Nulls[j] = To_Nulls[j];}
- virtual void SetNull(int n, bool b)
- {if (To_Nulls) {To_Nulls[n] = (b) ? '*' : 0;}}
- virtual bool IsNull(int n) {return To_Nulls && To_Nulls[n];}
- virtual void SetNullable(bool b);
- virtual bool IsUnsigned(void) {return Unsigned;}
- virtual void Init(PGLOBAL g, bool check) = 0;
- virtual int GetVlen(void) = 0;
- virtual PSZ GetCharValue(int n);
- virtual char GetTinyValue(int n) = 0;
- virtual uchar GetUTinyValue(int n) = 0;
- virtual short GetShortValue(int n) = 0;
- virtual ushort GetUShortValue(int n) = 0;
- virtual int GetIntValue(int n) = 0;
- virtual uint GetUIntValue(int n) = 0;
- 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);
- virtual void SetPrec(int p) {}
- virtual bool IsCi(void) {return false;}
-
- // Methods
- virtual void SetValue(short sval, int n) {assert(false);}
- virtual void SetValue(ushort sval, int n) {assert(false);}
- virtual void SetValue(int lval, int n) {assert(false);}
- virtual void SetValue(uint lval, int n) {assert(false);}
- virtual void SetValue(longlong lval, int n) {assert(false);}
- virtual void SetValue(ulonglong lval, int n) {assert(false);}
- virtual void SetValue(double fval, int n) {assert(false);}
- virtual void SetValue(char cval, int n) {assert(false);}
- virtual void SetValue(uchar cval, int n) {assert(false);}
- virtual void SetValue(PSZ sp, int n) {assert(false);}
- virtual void SetValue(char *sp, uint len, int n) {assert(false);}
- virtual void SetValue(PVAL valp, int n) = 0;
- virtual void SetValue(PVBLK pv, int n1, int n2) = 0;
- virtual void SetMin(PVAL valp, int n) = 0;
- virtual void SetMax(PVAL valp, int n) = 0;
- virtual void Move(int i, int j) = 0;
- virtual int CompVal(PVAL vp, int n) = 0;
- virtual int CompVal(int i1, int i2) = 0;
- virtual void *GetValPtr(int n) = 0;
- virtual void *GetValPtrEx(int n) = 0;
- virtual int Find(PVAL vp) = 0;
- virtual int GetMaxLength(void) = 0;
- bool Locate(PVAL vp, int& i);
-
- protected:
- void ChkIndx(int n);
- void ChkTyp(PVAL v);
- void ChkTyp(PVBLK vb);
-
- // Members
- PGLOBAL Global; // Used for messages and allocation
- char *To_Nulls; // Null values array
- void *Blkp; // To value block
- bool Check; // If true SetValue types must match
- bool Nullable; // True if values can be null
- bool Unsigned; // True if values are unsigned
- int Type; // Type of individual values
- int Nval; // Max number of values in block
- int Prec; // Precision of float values
- }; // end of class VALBLK
-
-/***********************************************************************/
-/* Class TYPBLK: represents a block of typed values. */
-/***********************************************************************/
-template <class TYPE>
-class TYPBLK : public VALBLK {
- public:
- // Constructors
- TYPBLK(void *mp, int size, int type, int prec = 0, bool un = false);
-
- // Implementation
- virtual void Init(PGLOBAL g, bool check);
- virtual int GetVlen(void) {return sizeof(TYPE);}
- virtual char GetTinyValue(int n) {return (char)Typp[n];}
- virtual uchar GetUTinyValue(int n) {return (uchar)Typp[n];}
- virtual short GetShortValue(int n) {return (short)Typp[n];}
- virtual ushort GetUShortValue(int n) {return (ushort)Typp[n];}
- virtual int GetIntValue(int n) {return (int)Typp[n];}
- virtual uint GetUIntValue(int n) {return (uint)Typp[n];}
- 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
- virtual void SetValue(PSZ sp, int n);
- virtual void SetValue(char *sp, uint len, int n);
- virtual void SetValue(short sval, int n)
- {Typp[n] = (TYPE)sval; SetNull(n, false);}
- virtual void SetValue(ushort sval, int n)
- {Typp[n] = (TYPE)sval; SetNull(n, false);}
- virtual void SetValue(int lval, int n)
- {Typp[n] = (TYPE)lval; SetNull(n, false);}
- virtual void SetValue(uint lval, int n)
- {Typp[n] = (TYPE)lval; SetNull(n, false);}
- virtual void SetValue(longlong lval, int n)
- {Typp[n] = (TYPE)lval; SetNull(n, false);}
- virtual void SetValue(ulonglong lval, int n)
- {Typp[n] = (TYPE)lval; SetNull(n, false);}
- virtual void SetValue(double fval, int n)
- {Typp[n] = (TYPE)fval; SetNull(n, false);}
- virtual void SetValue(char cval, int n)
- {Typp[n] = (TYPE)cval; SetNull(n, false);}
- virtual void SetValue(uchar cval, int n)
- {Typp[n] = (TYPE)cval; SetNull(n, false);}
- virtual void SetValue(PVAL valp, int n);
- virtual void SetValue(PVBLK pv, int n1, int n2);
- virtual void SetMin(PVAL valp, int n);
- virtual void SetMax(PVAL valp, int n);
- virtual void Move(int i, int j);
- virtual int CompVal(PVAL vp, int n);
- virtual int CompVal(int i1, int i2);
- virtual void *GetValPtr(int n);
- virtual void *GetValPtrEx(int n);
- virtual int Find(PVAL vp);
- virtual int GetMaxLength(void);
-
- protected:
- // Specialized functions
- static ulonglong MaxVal(void);
- TYPE GetTypedValue(PVAL vp);
- TYPE GetTypedValue(PVBLK blk, int n);
-
- // Members
- TYPE* const &Typp;
- const char *Fmt;
- }; // end of class TYPBLK
-
-/***********************************************************************/
-/* Class CHRBLK: represent a block of fixed length strings. */
-/***********************************************************************/
-class CHRBLK : public VALBLK {
- public:
- // Constructors
- CHRBLK(void *mp, int size, int len, int prec, bool b);
-
- // Implementation
- virtual void Init(PGLOBAL g, bool check);
- virtual int GetVlen(void) {return Long;}
- virtual PSZ GetCharValue(int n);
- virtual char GetTinyValue(int n);
- virtual uchar GetUTinyValue(int n);
- virtual short GetShortValue(int n);
- virtual ushort GetUShortValue(int n);
- virtual int GetIntValue(int n);
- virtual uint GetUIntValue(int n);
- 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;}
-
- // Methods
- virtual void SetValue(PSZ sp, int n);
- virtual void SetValue(char *sp, uint len, int n);
- virtual void SetValue(PVAL valp, int n);
- virtual void SetValue(PVBLK pv, int n1, int n2);
- virtual void SetMin(PVAL valp, int n);
- virtual void SetMax(PVAL valp, int n);
- virtual void Move(int i, int j);
- virtual int CompVal(PVAL vp, int n);
- virtual int CompVal(int i1, int i2);
- virtual void *GetValPtr(int n);
- virtual void *GetValPtrEx(int n);
- virtual int Find(PVAL vp);
- virtual int GetMaxLength(void);
-
- protected:
- // Members
- char* const &Chrp; // Pointer to char buffer
- PSZ Valp; // Used to make a zero ended value
- bool Blanks; // True for right filling with blanks
- bool Ci; // True if case insensitive
- int Long; // Length of each string
- }; // end of class CHRBLK
-
-/***********************************************************************/
-/* Class STRBLK: represent a block of string pointers. */
-/* Currently this class is used only by the DECODE scalar function */
-/* and by the MyColumn function to store date formats. */
-/***********************************************************************/
-class STRBLK : public VALBLK {
- public:
- // Constructors
- STRBLK(PGLOBAL g, void *mp, int size);
-
- // Implementation
- virtual void SetNull(int n, bool b) {if (b) {Strp[n] = NULL;}}
- virtual bool IsNull(int n) {return Strp[n] == NULL;}
- virtual void SetNullable(bool b) {} // Always nullable
- virtual void Init(PGLOBAL g, bool check);
- virtual int GetVlen(void) {return sizeof(PSZ);}
- virtual PSZ GetCharValue(int n) {return Strp[n];}
- virtual char GetTinyValue(int n);
- virtual uchar GetUTinyValue(int n);
- virtual short GetShortValue(int n);
- virtual ushort GetUShortValue(int n);
- virtual int GetIntValue(int n);
- virtual uint GetUIntValue(int n);
- 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
- virtual void SetValue(PSZ sp, int n);
- virtual void SetValue(char *sp, uint len, int n);
- virtual void SetValue(PVAL valp, int n);
- virtual void SetValue(PVBLK pv, int n1, int n2);
- virtual void SetMin(PVAL valp, int n);
- virtual void SetMax(PVAL valp, int n);
- virtual void Move(int i, int j);
- virtual int CompVal(PVAL vp, int n);
- virtual int CompVal(int i1, int i2);
- virtual void *GetValPtr(int n);
- virtual void *GetValPtrEx(int n);
- virtual int Find(PVAL vp);
- virtual int GetMaxLength(void);
-
- // Specific
- void SetSorted(bool b) {Sorted = b;}
-
- protected:
- // Members
- PSZ* const &Strp; // Pointer to PSZ buffer
- bool Sorted; // Values are (semi?) sorted
- }; // end of class STRBLK
-
-/***********************************************************************/
-/* Class DATBLK: represents a block of time stamp values. */
-/***********************************************************************/
-class DATBLK : public TYPBLK<int> {
- public:
- // Constructor
- DATBLK(void *mp, int size);
-
- // Implementation
- 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);
-
- protected:
- // Members
- PVAL Dvalp; // Date value used to convert string
- }; // end of class DATBLK
-
-#endif // __VALBLK__H__
-
+/***********************************************************************/
+/* Class VALBLK represent a base class for variable blocks. */
+/***********************************************************************/
+class VALBLK : public BLOCK {
+ public:
+ // Constructors
+ VALBLK(void *mp, int type, int nval, bool un = false);
+
+ // Implementation
+ int GetNval(void) {return Nval;}
+ void SetNval(int n) {Nval = n;}
+ void *GetValPointer(void) {return Blkp;}
+ void SetValPointer(void *mp) {Blkp = mp;}
+ int GetType(void) {return Type;}
+ int GetPrec(void) {return Prec;}
+ void SetCheck(bool b) {Check = b;}
+ void MoveNull(int i, int j)
+ {if (To_Nulls) To_Nulls[j] = To_Nulls[j];}
+ virtual void SetNull(int n, bool b)
+ {if (To_Nulls) {To_Nulls[n] = (b) ? '*' : 0;}}
+ virtual bool IsNull(int n) {return To_Nulls && To_Nulls[n];}
+ virtual void SetNullable(bool b);
+ virtual bool IsUnsigned(void) {return Unsigned;}
+ virtual bool Init(PGLOBAL g, bool check) = 0;
+ virtual int GetVlen(void) = 0;
+ virtual PSZ GetCharValue(int n);
+ virtual char GetTinyValue(int n) = 0;
+ virtual uchar GetUTinyValue(int n) = 0;
+ virtual short GetShortValue(int n) = 0;
+ virtual ushort GetUShortValue(int n) = 0;
+ virtual int GetIntValue(int n) = 0;
+ virtual uint GetUIntValue(int n) = 0;
+ 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);
+ virtual void SetPrec(int p) {}
+ virtual bool IsCi(void) {return false;}
+
+ // Methods
+ virtual void SetValue(short sval, int n) {assert(false);}
+ virtual void SetValue(ushort sval, int n) {assert(false);}
+ virtual void SetValue(int lval, int n) {assert(false);}
+ virtual void SetValue(uint lval, int n) {assert(false);}
+ virtual void SetValue(longlong lval, int n) {assert(false);}
+ virtual void SetValue(ulonglong lval, int n) {assert(false);}
+ virtual void SetValue(double fval, int n) {assert(false);}
+ virtual void SetValue(char cval, int n) {assert(false);}
+ virtual void SetValue(uchar cval, int n) {assert(false);}
+ virtual void SetValue(PSZ sp, int n) {assert(false);}
+ virtual void SetValue(char *sp, uint len, int n) {assert(false);}
+ virtual void SetValue(PVAL valp, int n) = 0;
+ virtual void SetValue(PVBLK pv, int n1, int n2) = 0;
+ virtual void SetMin(PVAL valp, int n) = 0;
+ virtual void SetMax(PVAL valp, int n) = 0;
+ virtual void Move(int i, int j) = 0;
+ virtual int CompVal(PVAL vp, int n) = 0;
+ virtual int CompVal(int i1, int i2) = 0;
+ virtual void *GetValPtr(int n) = 0;
+ virtual void *GetValPtrEx(int n) = 0;
+ virtual int Find(PVAL vp) = 0;
+ virtual int GetMaxLength(void) = 0;
+ bool Locate(PVAL vp, int& i);
+
+ protected:
+ bool AllocBuff(PGLOBAL g, size_t size);
+ void ChkIndx(int n);
+ void ChkTyp(PVAL v);
+ void ChkTyp(PVBLK vb);
+
+ // Members
+ PGLOBAL Global; // Used for messages and allocation
+ MBLOCK Mblk; // Used to allocate buffer
+ char *To_Nulls; // Null values array
+ void *Blkp; // To value block
+ bool Check; // If true SetValue types must match
+ bool Nullable; // True if values can be null
+ bool Unsigned; // True if values are unsigned
+ int Type; // Type of individual values
+ int Nval; // Max number of values in block
+ int Prec; // Precision of float values
+ }; // end of class VALBLK
+
+/***********************************************************************/
+/* Class TYPBLK: represents a block of typed values. */
+/***********************************************************************/
+template <class TYPE>
+class TYPBLK : public VALBLK {
+ public:
+ // Constructors
+ TYPBLK(void *mp, int size, int type, int prec = 0, bool un = false);
+
+ // Implementation
+ virtual bool Init(PGLOBAL g, bool check);
+ virtual int GetVlen(void) {return sizeof(TYPE);}
+ virtual char GetTinyValue(int n) {return (char)Typp[n];}
+ virtual uchar GetUTinyValue(int n) {return (uchar)Typp[n];}
+ virtual short GetShortValue(int n) {return (short)Typp[n];}
+ virtual ushort GetUShortValue(int n) {return (ushort)Typp[n];}
+ virtual int GetIntValue(int n) {return (int)Typp[n];}
+ virtual uint GetUIntValue(int n) {return (uint)Typp[n];}
+ 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
+ virtual void SetValue(PSZ sp, int n);
+ virtual void SetValue(char *sp, uint len, int n);
+ virtual void SetValue(short sval, int n)
+ {Typp[n] = (TYPE)sval; SetNull(n, false);}
+ virtual void SetValue(ushort sval, int n)
+ {Typp[n] = (TYPE)sval; SetNull(n, false);}
+ virtual void SetValue(int lval, int n)
+ {Typp[n] = (TYPE)lval; SetNull(n, false);}
+ virtual void SetValue(uint lval, int n)
+ {Typp[n] = (TYPE)lval; SetNull(n, false);}
+ virtual void SetValue(longlong lval, int n)
+ {Typp[n] = (TYPE)lval; SetNull(n, false);}
+ virtual void SetValue(ulonglong lval, int n)
+ {Typp[n] = (TYPE)lval; SetNull(n, false);}
+ virtual void SetValue(double fval, int n)
+ {Typp[n] = (TYPE)fval; SetNull(n, false);}
+ virtual void SetValue(char cval, int n)
+ {Typp[n] = (TYPE)cval; SetNull(n, false);}
+ virtual void SetValue(uchar cval, int n)
+ {Typp[n] = (TYPE)cval; SetNull(n, false);}
+ virtual void SetValue(PVAL valp, int n);
+ virtual void SetValue(PVBLK pv, int n1, int n2);
+ virtual void SetMin(PVAL valp, int n);
+ virtual void SetMax(PVAL valp, int n);
+ virtual void Move(int i, int j);
+ virtual int CompVal(PVAL vp, int n);
+ virtual int CompVal(int i1, int i2);
+ virtual void *GetValPtr(int n);
+ virtual void *GetValPtrEx(int n);
+ virtual int Find(PVAL vp);
+ virtual int GetMaxLength(void);
+
+ protected:
+ // Specialized functions
+ static ulonglong MaxVal(void);
+ TYPE GetTypedValue(PVAL vp);
+ TYPE GetTypedValue(PVBLK blk, int n);
+
+ // Members
+ TYPE* const &Typp;
+ const char *Fmt;
+ }; // end of class TYPBLK
+
+/***********************************************************************/
+/* Class CHRBLK: represent a block of fixed length strings. */
+/***********************************************************************/
+class CHRBLK : public VALBLK {
+ public:
+ // Constructors
+ CHRBLK(void *mp, int size, int len, int prec, bool b);
+
+ // Implementation
+ virtual bool Init(PGLOBAL g, bool check);
+ virtual int GetVlen(void) {return Long;}
+ virtual PSZ GetCharValue(int n);
+ virtual char GetTinyValue(int n);
+ virtual uchar GetUTinyValue(int n);
+ virtual short GetShortValue(int n);
+ virtual ushort GetUShortValue(int n);
+ virtual int GetIntValue(int n);
+ virtual uint GetUIntValue(int n);
+ 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;}
+
+ // Methods
+ virtual void SetValue(PSZ sp, int n);
+ virtual void SetValue(char *sp, uint len, int n);
+ virtual void SetValue(PVAL valp, int n);
+ virtual void SetValue(PVBLK pv, int n1, int n2);
+ virtual void SetMin(PVAL valp, int n);
+ virtual void SetMax(PVAL valp, int n);
+ virtual void Move(int i, int j);
+ virtual int CompVal(PVAL vp, int n);
+ virtual int CompVal(int i1, int i2);
+ virtual void *GetValPtr(int n);
+ virtual void *GetValPtrEx(int n);
+ virtual int Find(PVAL vp);
+ virtual int GetMaxLength(void);
+
+ protected:
+ // Members
+ char* const &Chrp; // Pointer to char buffer
+ PSZ Valp; // Used to make a zero ended value
+ bool Blanks; // True for right filling with blanks
+ bool Ci; // True if case insensitive
+ int Long; // Length of each string
+ }; // end of class CHRBLK
+
+/***********************************************************************/
+/* Class STRBLK: represent a block of string pointers. */
+/* Currently this class is used only by the DECODE scalar function */
+/* and by the MyColumn function to store date formats. */
+/***********************************************************************/
+class STRBLK : public VALBLK {
+ public:
+ // Constructors
+ STRBLK(PGLOBAL g, void *mp, int size);
+
+ // Implementation
+ virtual void SetNull(int n, bool b) {if (b) {Strp[n] = NULL;}}
+ virtual bool IsNull(int n) {return Strp[n] == NULL;}
+ virtual void SetNullable(bool b) {} // Always nullable
+ virtual bool Init(PGLOBAL g, bool check);
+ virtual int GetVlen(void) {return sizeof(PSZ);}
+ virtual PSZ GetCharValue(int n) {return Strp[n];}
+ virtual char GetTinyValue(int n);
+ virtual uchar GetUTinyValue(int n);
+ virtual short GetShortValue(int n);
+ virtual ushort GetUShortValue(int n);
+ virtual int GetIntValue(int n);
+ virtual uint GetUIntValue(int n);
+ 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
+ virtual void SetValue(PSZ sp, int n);
+ virtual void SetValue(char *sp, uint len, int n);
+ virtual void SetValue(PVAL valp, int n);
+ virtual void SetValue(PVBLK pv, int n1, int n2);
+ virtual void SetMin(PVAL valp, int n);
+ virtual void SetMax(PVAL valp, int n);
+ virtual void Move(int i, int j);
+ virtual int CompVal(PVAL vp, int n);
+ virtual int CompVal(int i1, int i2);
+ virtual void *GetValPtr(int n);
+ virtual void *GetValPtrEx(int n);
+ virtual int Find(PVAL vp);
+ virtual int GetMaxLength(void);
+
+ // Specific
+ void SetSorted(bool b) {Sorted = b;}
+
+ protected:
+ // Members
+ PSZ* const &Strp; // Pointer to PSZ buffer
+ bool Sorted; // Values are (semi?) sorted
+ }; // end of class STRBLK
+
+/***********************************************************************/
+/* Class DATBLK: represents a block of time stamp values. */
+/***********************************************************************/
+class DATBLK : public TYPBLK<int> {
+ public:
+ // Constructor
+ DATBLK(void *mp, int size);
+
+ // Implementation
+ 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);
+
+ protected:
+ // Members
+ PVAL Dvalp; // Date value used to convert string
+ }; // end of class DATBLK
+
+#endif // __VALBLK__H__
+
diff --git a/storage/connect/value.cpp b/storage/connect/value.cpp
index 654cf1d6907..abeea89232b 100644
--- a/storage/connect/value.cpp
+++ b/storage/connect/value.cpp
@@ -1,5 +1,5 @@
/************* Value C++ Functions Source Code File (.CPP) *************/
-/* Name: VALUE.CPP Version 2.4 */
+/* Name: VALUE.CPP Version 2.5 */
/* */
/* (C) Copyright to the author Olivier BERTRAND 2001-2014 */
/* */
@@ -183,6 +183,7 @@ PSZ GetTypeName(int type)
case TYPE_DOUBLE: name = "DOUBLE"; break;
case TYPE_TINY: name = "TINY"; break;
case TYPE_DECIM: name = "DECIMAL"; break;
+ case TYPE_BIN: name = "BINARY"; break;
default: name = "UNKNOWN"; break;
} // endswitch type
@@ -196,6 +197,7 @@ int GetTypeSize(int type, int len)
{
switch (type) {
case TYPE_DECIM:
+ case TYPE_BIN:
case TYPE_STRING: len = len * sizeof(char); break;
case TYPE_SHORT: len = sizeof(short); break;
case TYPE_INT: len = sizeof(int); break;
@@ -225,6 +227,7 @@ char *GetFormatType(int type)
case TYPE_DATE: c = "D"; break;
case TYPE_TINY: c = "T"; break;
case TYPE_DECIM: c = "M"; break;
+ case TYPE_BIN: c = "B"; break;
} // endswitch type
return c;
@@ -246,6 +249,7 @@ int GetFormatType(char c)
case 'D': type = TYPE_DATE; break;
case 'T': type = TYPE_TINY; break;
case 'M': type = TYPE_DECIM; break;
+ case 'B': type = TYPE_BIN; break;
} // endswitch type
return type;
@@ -298,6 +302,7 @@ const char *GetFmt(int type, bool un)
case TYPE_SHORT: fmt = (un) ? "%hu" : "%hd"; break;
case TYPE_BIGINT: fmt = (un) ? "%llu" : "%lld"; break;
case TYPE_DOUBLE: fmt = "%.*lf"; break;
+ case TYPE_BIN: fmt = "%*x"; break;
default: fmt = (un) ? "%u" : "%d"; break;
} // endswitch Type
@@ -438,6 +443,9 @@ PVAL AllocateValue(PGLOBAL g, int type, int len, int prec,
case TYPE_DECIM:
valp = new(g) DECVAL(g, (PSZ)NULL, len, prec, uns);
break;
+ case TYPE_BIN:
+ valp = new(g) BINVAL(g, (void*)NULL, len, prec);
+ break;
default:
sprintf(g->Message, MSG(BAD_VALUE_TYPE), type);
return NULL;
@@ -544,6 +552,7 @@ const char *VALUE::GetXfmt(void)
case TYPE_SHORT: fmt = (Unsigned) ? "%*hu" : "%*hd"; break;
case TYPE_BIGINT: fmt = (Unsigned) ? "%*llu" : "%*lld"; break;
case TYPE_DOUBLE: fmt = "%*.*lf"; break;
+ case TYPE_BIN: fmt = "%*x"; break;
default: fmt = (Unsigned) ? "%*u" : "%*d"; break;
} // endswitch Type
@@ -1695,6 +1704,426 @@ bool DECVAL::SetConstFormat(PGLOBAL g, FORMAT& fmt)
} // end of SetConstFormat
#endif // 0
+/* -------------------------- Class BINVAL --------------------------- */
+
+/***********************************************************************/
+/* BINVAL public constructor from bytes. */
+/***********************************************************************/
+BINVAL::BINVAL(PGLOBAL g, void *p, int cl, int n) : VALUE(TYPE_BIN)
+ {
+ assert(g);
+ Len = n;
+ Clen = cl;
+ Binp = PlugSubAlloc(g, NULL, Clen + 1);
+ memset(Binp, 0, Clen + 1);
+
+ if (p)
+ memcpy(Binp, p, Len);
+
+ Chrp = NULL;
+ } // end of BINVAL constructor
+
+/***********************************************************************/
+/* BINVAL: Check whether the hexadecimal value is equal to 0. */
+/***********************************************************************/
+bool BINVAL::IsZero(void)
+ {
+ for (int i = 0; i < Len; i++)
+ if (((char*)Binp)[i] != 0)
+ return false;
+
+ return true;
+ } // end of IsZero
+
+/***********************************************************************/
+/* BINVAL: Reset value to zero. */
+/***********************************************************************/
+void BINVAL::Reset(void)
+{
+ memset(Binp, 0, Clen);
+ Len = 0;
+} // end of Reset
+
+/***********************************************************************/
+/* Get the tiny value pointed by Binp. */
+/***********************************************************************/
+char BINVAL::GetTinyValue(void)
+ {
+ return *(char*)Binp;
+ } // end of GetTinyValue
+
+/***********************************************************************/
+/* Get the unsigned tiny value pointed by Binp. */
+/***********************************************************************/
+uchar BINVAL::GetUTinyValue(void)
+ {
+ return *(uchar*)Binp;
+ } // end of GetUTinyValue
+
+/***********************************************************************/
+/* Get the short value pointed by Binp. */
+/***********************************************************************/
+short BINVAL::GetShortValue(void)
+ {
+ if (Len >= 2)
+ return *(short*)Binp;
+ else
+ return (short)GetTinyValue();
+
+ } // end of GetShortValue
+
+/***********************************************************************/
+/* Get the unsigned short value pointed by Binp. */
+/***********************************************************************/
+ushort BINVAL::GetUShortValue(void)
+ {
+ return (ushort)GetShortValue();
+ } // end of GetUshortValue
+
+/***********************************************************************/
+/* Get the integer value pointed by Binp. */
+/***********************************************************************/
+int BINVAL::GetIntValue(void)
+ {
+ if (Len >= 4)
+ return *(int*)Binp;
+ else
+ return (int)GetShortValue();
+
+ } // end of GetIntValue
+
+/***********************************************************************/
+/* Get the unsigned integer value pointed by Binp. */
+/***********************************************************************/
+uint BINVAL::GetUIntValue(void)
+ {
+ return (uint)GetIntValue();
+ } // end of GetUintValue
+
+/***********************************************************************/
+/* Get the big integer value pointed by Binp. */
+/***********************************************************************/
+longlong BINVAL::GetBigintValue(void)
+ {
+ if (Len >= 8)
+ return *(longlong*)Binp;
+ else
+ return (longlong)GetIntValue();
+
+ } // end of GetBigintValue
+
+/***********************************************************************/
+/* Get the unsigned big integer value pointed by Binp. */
+/***********************************************************************/
+ulonglong BINVAL::GetUBigintValue(void)
+ {
+ return (ulonglong)GetBigintValue();
+ } // end of GetUBigintValue
+
+/***********************************************************************/
+/* Get the double value pointed by Binp. */
+/***********************************************************************/
+double BINVAL::GetFloatValue(void)
+{
+ if (Len >= 8)
+ return *(double*)Binp;
+ else if (Len >= 4)
+ return (double)(*(float*)Binp);
+ else
+ return 0.0;
+
+} // end of GetFloatValue
+
+/***********************************************************************/
+/* BINVAL SetValue: copy the value of another Value object. */
+/***********************************************************************/
+bool BINVAL::SetValue_pval(PVAL valp, bool chktype)
+ {
+ if (chktype && (valp->GetType() != Type || valp->GetSize() > Clen))
+ return true;
+
+ bool rc = false;
+
+ if (!(Null = valp->IsNull() && Nullable)) {
+ if ((rc = (Len = valp->GetSize()) > Clen))
+ Len = Clen;
+
+ memcpy(Binp, valp->GetTo_Val(), Len);
+ } else
+ Reset();
+
+ return rc;
+ } // end of SetValue_pval
+
+/***********************************************************************/
+/* BINVAL SetValue: fill value with chars extracted from a line. */
+/***********************************************************************/
+bool BINVAL::SetValue_char(char *p, int n)
+ {
+ bool rc;
+
+ if (p) {
+ rc = n > Clen;
+ Len = min(n, Clen);
+ memcpy(Binp, p, Len);
+ Null = false;
+ } else {
+ rc = false;
+ Reset();
+ Null = Nullable;
+ } // endif p
+
+ return rc;
+ } // end of SetValue_char
+
+/***********************************************************************/
+/* BINVAL SetValue: fill value with another string. */
+/***********************************************************************/
+void BINVAL::SetValue_psz(PSZ s)
+ {
+ if (s) {
+ Len = min(Clen, (signed)strlen(s));
+ memcpy(Binp, s, Len);
+ Null = false;
+ } else {
+ Reset();
+ Null = Nullable;
+ } // endif s
+
+ } // end of SetValue_psz
+
+/***********************************************************************/
+/* BINVAL SetValue: fill value with bytes extracted from a block. */
+/***********************************************************************/
+void BINVAL::SetValue_pvblk(PVBLK blk, int n)
+ {
+ // STRBLK's can return a NULL pointer
+ void *vp = blk->GetValPtrEx(n);
+
+ if (!vp || blk->IsNull(n)) {
+ Reset();
+ Null = Nullable;
+ } else if (vp != Binp) {
+ if (blk->GetType() == TYPE_STRING)
+ Len = strlen((char*)vp);
+ else
+ Len = blk->GetVlen();
+
+ Len = min(Clen, Len);
+ memcpy(Binp, vp, Len);
+ Null = false;
+ } // endif vp
+
+ } // end of SetValue_pvblk
+
+/***********************************************************************/
+/* BINVAL SetValue: get the binary representation of an integer. */
+/***********************************************************************/
+void BINVAL::SetValue(int n)
+ {
+ if (Clen >= 4) {
+ *((int*)Binp) = n;
+ Len = 4;
+ } else
+ SetValue((short)n);
+
+ } // end of SetValue
+
+/***********************************************************************/
+/* BINVAL SetValue: get the binary representation of an uint. */
+/***********************************************************************/
+void BINVAL::SetValue(uint n)
+ {
+ if (Clen >= 4) {
+ *((uint*)Binp) = n;
+ Len = 4;
+ } else
+ SetValue((ushort)n);
+
+ } // end of SetValue
+
+/***********************************************************************/
+/* BINVAL SetValue: get the binary representation of a short int. */
+/***********************************************************************/
+void BINVAL::SetValue(short i)
+ {
+ if (Clen >= 2) {
+ *((int*)Binp) = i;
+ Len = 2;
+ } else
+ SetValue((char)i);
+
+ } // end of SetValue
+
+/***********************************************************************/
+/* BINVAL SetValue: get the binary representation of a ushort int. */
+/***********************************************************************/
+void BINVAL::SetValue(ushort i)
+ {
+ if (Clen >= 2) {
+ *((uint*)Binp) = i;
+ Len = 2;
+ } else
+ SetValue((uchar)i);
+
+ } // end of SetValue
+
+/***********************************************************************/
+/* BINVAL SetValue: get the binary representation of a big integer. */
+/***********************************************************************/
+void BINVAL::SetValue(longlong n)
+ {
+ if (Clen >= 8) {
+ *((longlong*)Binp) = n;
+ Len = 8;
+ } else
+ SetValue((int)n);
+
+ } // end of SetValue
+
+/***********************************************************************/
+/* BINVAL SetValue: get the binary representation of a big integer. */
+/***********************************************************************/
+void BINVAL::SetValue(ulonglong n)
+ {
+ if (Clen >= 8) {
+ *((ulonglong*)Binp) = n;
+ Len = 8;
+ } else
+ SetValue((uint)n);
+ } // end of SetValue
+
+/***********************************************************************/
+/* BINVAL SetValue: get the binary representation of a double. */
+/***********************************************************************/
+void BINVAL::SetValue(double n)
+ {
+ if (Clen >= 8) {
+ *((double*)Binp) = n;
+ Len = 8;
+ } else if (Clen >= 4) {
+ *((float*)Binp) = (float)n;
+ Len = 4;
+ } else
+ Len = 0;
+
+ } // end of SetValue
+
+/***********************************************************************/
+/* BINVAL SetValue: get the character binary of a tiny int. */
+/***********************************************************************/
+void BINVAL::SetValue(char c)
+ {
+ *((char*)Binp) = c;
+ Len = 1;
+ } // end of SetValue
+
+/***********************************************************************/
+/* BINVAL SetValue: get the binary representation of a tiny int. */
+/***********************************************************************/
+void BINVAL::SetValue(uchar c)
+ {
+ *((uchar*)Binp) = c;
+ Len = 1;
+ } // end of SetValue
+
+/***********************************************************************/
+/* BINVAL SetBinValue: fill string with bytes extracted from a line. */
+/***********************************************************************/
+void BINVAL::SetBinValue(void *p)
+ {
+ memcpy(Binp, p, Clen);
+ } // end of SetBinValue
+
+/***********************************************************************/
+/* GetBinValue: fill a buffer with the internal binary value. */
+/* This function checks whether the buffer length is enough and */
+/* returns true if not. Actual filling occurs only if go is true. */
+/* Currently used by WriteColumn of binary files. */
+/***********************************************************************/
+bool BINVAL::GetBinValue(void *buf, int buflen, bool go)
+ {
+ if (Len > buflen)
+ return true;
+ else if (go) {
+ memset(buf, 0, buflen);
+ memcpy(buf, Binp, Len);
+ } // endif go
+
+ return false;
+ } // end of GetBinValue
+
+/***********************************************************************/
+/* BINVAL ShowValue: get string representation of a binary value. */
+/***********************************************************************/
+char *BINVAL::ShowValue(char *buf, int len)
+ {
+ int n = min(Len, len / 2);
+
+ sprintf(buf, GetXfmt(), n, Binp);
+ return buf;
+ } // end of ShowValue
+
+/***********************************************************************/
+/* BINVAL GetCharString: get string representation of a binary value. */
+/***********************************************************************/
+char *BINVAL::GetCharString(char *p)
+ {
+ if (!Chrp)
+ Chrp = (char*)PlugSubAlloc(Global, NULL, Clen * 2 + 1);
+
+ sprintf(Chrp, GetXfmt(), Len, Binp);
+ return Chrp;
+ } // end of GetCharString
+
+/***********************************************************************/
+/* BINVAL compare value with another Value. */
+/***********************************************************************/
+bool BINVAL::IsEqual(PVAL vp, bool chktype)
+ {
+ if (this == vp)
+ return true;
+ else if (chktype && Type != vp->GetType())
+ return false;
+ else if (Null || vp->IsNull())
+ return false;
+ else if (Len != vp->GetSize())
+ return false;
+
+ char *v1 = (char*)Binp;
+ char *v2 = (char*)vp->GetTo_Val();
+
+ for (int i = 0; i < Len; i++)
+ if (v1[i] != v2[i])
+ return false;
+
+ return true;
+ } // end of IsEqual
+
+/***********************************************************************/
+/* FormatValue: This function set vp (a STRING value) to the string */
+/* constructed from its own value formated using the fmt format. */
+/* This function assumes that the format matches the value type. */
+/***********************************************************************/
+bool BINVAL::FormatValue(PVAL vp, char *fmt)
+ {
+ char *buf = (char*)vp->GetTo_Val(); // Should be big enough
+ int n = sprintf(buf, fmt, Len, Binp);
+
+ return (n > vp->GetValLen());
+ } // end of FormatValue
+
+/***********************************************************************/
+/* BINVAL SetFormat function (used to set SELECT output format). */
+/***********************************************************************/
+bool BINVAL::SetConstFormat(PGLOBAL g, FORMAT& fmt)
+ {
+ fmt.Type[0] = 'B';
+ fmt.Length = Clen;
+ fmt.Prec = 0;
+ return false;
+ } // end of SetConstFormat
+
/* -------------------------- Class DTVAL ---------------------------- */
/***********************************************************************/
diff --git a/storage/connect/value.h b/storage/connect/value.h
index e9a899302c9..3dc7940b964 100644
--- a/storage/connect/value.h
+++ b/storage/connect/value.h
@@ -1,333 +1,390 @@
-/**************** Value H Declares Source Code File (.H) ***************/
-/* Name: VALUE.H Version 2.0 */
-/* */
-/* (C) Copyright to the author Olivier BERTRAND 2001-2013 */
-/* */
-/* This file contains the VALUE and derived classes declares. */
-/***********************************************************************/
-#ifndef __VALUE__H__
-#define __VALUE__H__
-
-/***********************************************************************/
-/* Include required application header files */
-/* assert.h is header required when using the assert function. */
-/* block.h is header containing Block global declarations. */
-/***********************************************************************/
-#include "assert.h"
-#include "block.h"
-
-/***********************************************************************/
-/* Types used in some class definitions. */
-/***********************************************************************/
-enum CONV {CNV_ANY = 0, /* Convert to any type */
- CNV_CHAR = 1, /* Convert to character type */
- CNV_NUM = 2}; /* Convert to numeric type */
-
-/***********************************************************************/
-/* Types used in some class definitions. */
-/***********************************************************************/
-class CONSTANT; // For friend setting
-typedef struct _datpar *PDTP; // For DTVAL
-
-
-/***********************************************************************/
-/* Utilities used to test types and to allocated values. */
-/***********************************************************************/
-PVAL AllocateValue(PGLOBAL, void *, short);
-
-// Exported functions
-DllExport PSZ GetTypeName(int);
-DllExport int GetTypeSize(int, int);
-#ifdef ODBC_SUPPORT
-/* This function is exported for use in EOM table type DLLs */
-DllExport int TranslateSQLType(int stp, int prec, int& len, char& v);
-#endif
-DllExport char *GetFormatType(int);
-DllExport int GetFormatType(char);
-DllExport bool IsTypeChar(int type);
-DllExport bool IsTypeNum(int type);
-DllExport int ConvertType(int, int, CONV, bool match = false);
-DllExport PVAL AllocateValue(PGLOBAL, PVAL, int = TYPE_VOID, int = 0);
-DllExport PVAL AllocateValue(PGLOBAL, int, int len = 0, int prec = 0,
- bool uns = false, PSZ fmt = NULL);
-DllExport ulonglong CharToNumber(char *, int, ulonglong, bool,
- bool *minus = NULL, bool *rc = NULL);
-
-/***********************************************************************/
-/* Class VALUE represents a constant or variable of any valid type. */
-/***********************************************************************/
-class DllExport VALUE : public BLOCK {
- friend class CONSTANT; // The only object allowed to use SetConstFormat
- public:
- // Constructors
-
- // Implementation
- virtual bool IsTypeNum(void) = 0;
- virtual bool IsZero(void) = 0;
- virtual bool IsCi(void) {return false;}
- virtual bool IsUnsigned(void) {return Unsigned;}
- virtual void Reset(void) = 0;
- virtual int GetSize(void) = 0;
- virtual int GetValLen(void) = 0;
- virtual int GetValPrec(void) = 0;
- virtual int GetLength(void) {return 1;}
- virtual PSZ GetCharValue(void) {assert(false); return NULL;}
- virtual char GetTinyValue(void) {assert(false); return 0;}
- virtual uchar GetUTinyValue(void) {assert(false); return 0;}
- virtual short GetShortValue(void) {assert(false); return 0;}
- virtual ushort GetUShortValue(void) {assert(false); return 0;}
- virtual int GetIntValue(void) = 0;
- virtual uint GetUIntValue(void) = 0;
- virtual longlong GetBigintValue(void) = 0;
- virtual ulonglong GetUBigintValue(void) = 0;
- virtual double GetFloatValue(void) = 0;
- virtual void *GetTo_Val(void) = 0;
- virtual void SetPrec(int prec) {Prec = prec;}
- bool IsNull(void) {return Null;}
- void SetNull(bool b) {Null = b;}
- bool GetNullable(void) {return Nullable;}
- void SetNullable(bool b) {Nullable = b;}
- int GetType(void) {return Type;}
- int GetClen(void) {return Clen;}
- void SetGlobal(PGLOBAL g) {Global = g;}
-
- // Methods
- virtual bool SetValue_pval(PVAL valp, bool chktype = false) = 0;
- virtual bool SetValue_char(char *p, int n) = 0;
- virtual void SetValue_psz(PSZ s) = 0;
- virtual void SetValue_bool(bool b) {assert(FALSE);}
- virtual int CompareValue(PVAL vp) = 0;
- virtual BYTE TestValue(PVAL vp);
- virtual void SetValue(char c) {assert(false);}
- virtual void SetValue(uchar c) {assert(false);}
- virtual void SetValue(short i) {assert(false);}
- virtual void SetValue(ushort i) {assert(false);}
- virtual void SetValue(int n) {assert(false);}
- virtual void SetValue(uint n) {assert(false);}
- virtual void SetValue(longlong n) {assert(false);}
- virtual void SetValue(ulonglong n) {assert(false);}
- virtual void SetValue(double f) {assert(false);}
- virtual void SetValue_pvblk(PVBLK blk, int n) = 0;
- virtual void SetBinValue(void *p) = 0;
- virtual bool GetBinValue(void *buf, int buflen, bool go) = 0;
- virtual char *ShowValue(char *buf, int len = 0) = 0;
- virtual char *GetCharString(char *p) = 0;
- virtual bool IsEqual(PVAL vp, bool chktype) = 0;
- virtual bool FormatValue(PVAL vp, char *fmt) = 0;
-
- protected:
- virtual bool SetConstFormat(PGLOBAL, FORMAT&) = 0;
- const char *GetXfmt(void);
-
- // Constructor used by derived classes
- VALUE(int type, bool un = false);
-
- // Members
- PGLOBAL Global; // To reduce arglist
- const char *Fmt;
- const char *Xfmt;
- bool Nullable; // True if value can be null
- bool Null; // True if value is null
- bool Unsigned; // True if unsigned
- int Type; // The value type
- int Clen; // Internal value length
- int Prec;
- }; // end of class VALUE
-
-/***********************************************************************/
-/* Class TYPVAL: represents a typed value. */
-/***********************************************************************/
-template <class TYPE>
-class DllExport TYPVAL : public VALUE {
- public:
- // Constructor
- TYPVAL(TYPE n, int type, int prec = 0, bool un = false);
-
- // Implementation
- virtual bool IsTypeNum(void) {return true;}
- virtual bool IsZero(void) {return Tval == 0;}
- virtual void Reset(void) {Tval = 0;}
- virtual int GetValLen(void);
- virtual int GetValPrec() {return 0;}
- virtual int GetSize(void) {return sizeof(TYPE);}
- virtual PSZ GetCharValue(void) {return VALUE::GetCharValue();}
- virtual char GetTinyValue(void) {return (char)Tval;}
- virtual uchar GetUTinyValue(void) {return (uchar)Tval;}
- virtual short GetShortValue(void) {return (short)Tval;}
- virtual ushort GetUShortValue(void) {return (ushort)Tval;}
- virtual int GetIntValue(void) {return (int)Tval;}
- virtual uint GetUIntValue(void) {return (uint)Tval;}
- virtual longlong GetBigintValue(void) {return (longlong)Tval;}
- virtual ulonglong GetUBigintValue(void) {return (ulonglong)Tval;}
- virtual double GetFloatValue(void) {return (double)Tval;}
- virtual void *GetTo_Val(void) {return &Tval;}
-
- // Methods
- virtual bool SetValue_pval(PVAL valp, bool chktype);
- virtual bool SetValue_char(char *p, int n);
- virtual void SetValue_psz(PSZ s);
- virtual void SetValue_bool(bool b) {Tval = (b) ? 1 : 0;}
- virtual int CompareValue(PVAL vp);
- virtual void SetValue(char c) {Tval = (TYPE)c; Null = false;}
- virtual void SetValue(uchar c) {Tval = (TYPE)c; Null = false;}
- virtual void SetValue(short i) {Tval = (TYPE)i; Null = false;}
- virtual void SetValue(ushort i) {Tval = (TYPE)i; Null = false;}
- virtual void SetValue(int n) {Tval = (TYPE)n; Null = false;}
- virtual void SetValue(uint n) {Tval = (TYPE)n; Null = false;}
- virtual void SetValue(longlong n) {Tval = (TYPE)n; Null = false;}
- virtual void SetValue(ulonglong n) {Tval = (TYPE)n; Null = false;}
- virtual void SetValue(double f) {Tval = (TYPE)f; Null = false;}
- virtual void SetValue_pvblk(PVBLK blk, int n);
- virtual void SetBinValue(void *p);
- virtual bool GetBinValue(void *buf, int buflen, bool go);
- virtual char *ShowValue(char *buf, int);
- virtual char *GetCharString(char *p);
- virtual bool IsEqual(PVAL vp, bool chktype);
- virtual bool SetConstFormat(PGLOBAL, FORMAT&);
- virtual bool FormatValue(PVAL vp, char *fmt);
- virtual void Print(PGLOBAL g, FILE *, uint);
- virtual void Print(PGLOBAL g, char *, uint);
-
- protected:
- // Default constructor not to be used
- TYPVAL(void) : VALUE(TYPE_ERROR) {}
-
- // Specialized functions
- static ulonglong MaxVal(void);
- TYPE GetTypedValue(PVAL vp);
- TYPE GetTypedValue(PVBLK blk, int n);
-// TYPE GetTypedValue(PSZ s);
-
- // Members
- TYPE Tval;
- }; // end of class TYPVAL
-
-/***********************************************************************/
-/* Specific STRING class. */
-/***********************************************************************/
-template <>
-class DllExport TYPVAL<PSZ>: public VALUE {
- public:
- // Constructors
- TYPVAL(PSZ s);
- TYPVAL(PGLOBAL g, PSZ s, int n, int c);
-
- // Implementation
- virtual bool IsTypeNum(void) {return false;}
- virtual bool IsZero(void) {return *Strp == 0;}
- virtual void Reset(void) {*Strp = 0;}
- virtual int GetValLen(void) {return Len;};
- virtual int GetValPrec() {return (Ci) ? 1 : 0;}
- virtual int GetSize(void) {return (Strp) ? strlen(Strp) : 0;}
- virtual PSZ GetCharValue(void) {return Strp;}
- virtual char GetTinyValue(void);
- virtual uchar GetUTinyValue(void);
- virtual short GetShortValue(void);
- virtual ushort GetUShortValue(void);
- virtual int GetIntValue(void);
- virtual uint GetUIntValue(void);
- virtual longlong GetBigintValue(void);
- virtual ulonglong GetUBigintValue(void);
- virtual double GetFloatValue(void) {return atof(Strp);}
- virtual void *GetTo_Val(void) {return Strp;}
- virtual void SetPrec(int prec) {Ci = prec != 0;}
-
- // Methods
- virtual bool SetValue_pval(PVAL valp, bool chktype);
- virtual bool SetValue_char(char *p, int n);
- virtual void SetValue_psz(PSZ s);
- virtual void SetValue_pvblk(PVBLK blk, int n);
- virtual void SetValue(char c);
- virtual void SetValue(uchar c);
- virtual void SetValue(short i);
- virtual void SetValue(ushort i);
- virtual void SetValue(int n);
- virtual void SetValue(uint n);
- virtual void SetValue(longlong n);
- virtual void SetValue(ulonglong n);
- virtual void SetValue(double f);
- virtual void SetBinValue(void *p);
- virtual int CompareValue(PVAL vp);
- virtual bool GetBinValue(void *buf, int buflen, bool go);
- virtual char *ShowValue(char *buf, int);
- virtual char *GetCharString(char *p);
- virtual bool IsEqual(PVAL vp, bool chktype);
- virtual bool FormatValue(PVAL vp, char *fmt);
- virtual bool SetConstFormat(PGLOBAL, FORMAT&);
-
- // Members
- PSZ Strp;
- bool Ci; // true if case insensitive
- int Len;
- }; // end of class TYPVAL<PSZ>
-
-/***********************************************************************/
-/* Specific DECIMAL class. */
-/***********************************************************************/
-class DllExport DECVAL: public TYPVAL<PSZ> {
- public:
- // Constructors
- DECVAL(PSZ s);
- DECVAL(PGLOBAL g, PSZ s, int n, int prec, bool uns);
-
- // Implementation
- virtual bool IsTypeNum(void) {return true;}
- virtual bool IsZero(void);
- virtual void Reset(void);
- virtual int GetValPrec() {return Prec;}
-
- // Methods
- virtual bool GetBinValue(void *buf, int buflen, bool go);
- virtual char *ShowValue(char *buf, int);
- virtual bool IsEqual(PVAL vp, bool chktype);
- virtual int CompareValue(PVAL vp);
-
- // Members
- }; // end of class DECVAL
-
-/***********************************************************************/
-/* Class DTVAL: represents a time stamp value. */
-/***********************************************************************/
-class DllExport DTVAL : public TYPVAL<int> {
- public:
- // Constructors
- DTVAL(PGLOBAL g, int n, int p, PSZ fmt);
- DTVAL(PGLOBAL g, PSZ s, int n);
- DTVAL(PGLOBAL g, short i);
- DTVAL(PGLOBAL g, int n);
- DTVAL(PGLOBAL g, longlong n);
- DTVAL(PGLOBAL g, double f);
-
- // Implementation
- virtual bool SetValue_pval(PVAL valp, bool chktype);
- virtual bool SetValue_char(char *p, int n);
- virtual void SetValue_psz(PSZ s);
- virtual void SetValue_pvblk(PVBLK blk, int n);
- virtual char *GetCharString(char *p);
- virtual char *ShowValue(char *buf, int);
- virtual bool FormatValue(PVAL vp, char *fmt);
- bool SetFormat(PGLOBAL g, PSZ fmt, int len, int year = 0);
- bool SetFormat(PGLOBAL g, PVAL valp);
- bool IsFormatted(void) {return Pdtp != NULL;}
- bool MakeTime(struct tm *ptm);
- static void SetTimeShift(void);
- static int GetShift(void) {return Shift;}
-
- // Methods
- bool MakeDate(PGLOBAL g, int *val, int nval);
-
- struct tm *GetGmTime(struct tm *);
-
- protected:
- // Default constructor not to be used
- DTVAL(void) : TYPVAL<int>() {}
-
- // Members
- static int Shift; // Time zone shift in seconds
- PDTP Pdtp; // To the DATPAR structure
- char *Sdate; // Utility char buffer
- int DefYear; // Used by ExtractDate
- int Len; // Used by CHAR scalar function
- }; // end of class DTVAL
-
-#endif // __VALUE__H__
+/**************** Value H Declares Source Code File (.H) ***************/
+/* Name: VALUE.H Version 2.1 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2001-2014 */
+/* */
+/* This file contains the VALUE and derived classes declares. */
+/***********************************************************************/
+#ifndef __VALUE__H__
+#define __VALUE__H__
+
+/***********************************************************************/
+/* Include required application header files */
+/* assert.h is header required when using the assert function. */
+/* block.h is header containing Block global declarations. */
+/***********************************************************************/
+#include "assert.h"
+#include "block.h"
+
+/***********************************************************************/
+/* Types used in some class definitions. */
+/***********************************************************************/
+enum CONV {CNV_ANY = 0, /* Convert to any type */
+ CNV_CHAR = 1, /* Convert to character type */
+ CNV_NUM = 2}; /* Convert to numeric type */
+
+/***********************************************************************/
+/* Types used in some class definitions. */
+/***********************************************************************/
+class CONSTANT; // For friend setting
+typedef struct _datpar *PDTP; // For DTVAL
+
+
+/***********************************************************************/
+/* Utilities used to test types and to allocated values. */
+/***********************************************************************/
+PVAL AllocateValue(PGLOBAL, void *, short);
+
+// Exported functions
+DllExport PSZ GetTypeName(int);
+DllExport int GetTypeSize(int, int);
+#ifdef ODBC_SUPPORT
+/* This function is exported for use in EOM table type DLLs */
+DllExport int TranslateSQLType(int stp, int prec, int& len, char& v);
+#endif
+DllExport char *GetFormatType(int);
+DllExport int GetFormatType(char);
+DllExport bool IsTypeChar(int type);
+DllExport bool IsTypeNum(int type);
+DllExport int ConvertType(int, int, CONV, bool match = false);
+DllExport PVAL AllocateValue(PGLOBAL, PVAL, int = TYPE_VOID, int = 0);
+DllExport PVAL AllocateValue(PGLOBAL, int, int len = 0, int prec = 0,
+ bool uns = false, PSZ fmt = NULL);
+DllExport ulonglong CharToNumber(char *, int, ulonglong, bool,
+ bool *minus = NULL, bool *rc = NULL);
+
+/***********************************************************************/
+/* Class VALUE represents a constant or variable of any valid type. */
+/***********************************************************************/
+class DllExport VALUE : public BLOCK {
+ friend class CONSTANT; // The only object allowed to use SetConstFormat
+ public:
+ // Constructors
+
+ // Implementation
+ virtual bool IsTypeNum(void) = 0;
+ virtual bool IsZero(void) = 0;
+ virtual bool IsCi(void) {return false;}
+ virtual bool IsUnsigned(void) {return Unsigned;}
+ virtual void Reset(void) = 0;
+ virtual int GetSize(void) = 0;
+ virtual int GetValLen(void) = 0;
+ virtual int GetValPrec(void) = 0;
+ virtual int GetLength(void) {return 1;}
+ virtual PSZ GetCharValue(void) {assert(false); return NULL;}
+ virtual char GetTinyValue(void) {assert(false); return 0;}
+ virtual uchar GetUTinyValue(void) {assert(false); return 0;}
+ virtual short GetShortValue(void) {assert(false); return 0;}
+ virtual ushort GetUShortValue(void) {assert(false); return 0;}
+ virtual int GetIntValue(void) = 0;
+ virtual uint GetUIntValue(void) = 0;
+ virtual longlong GetBigintValue(void) = 0;
+ virtual ulonglong GetUBigintValue(void) = 0;
+ virtual double GetFloatValue(void) = 0;
+ virtual void *GetTo_Val(void) = 0;
+ virtual void SetPrec(int prec) {Prec = prec;}
+ bool IsNull(void) {return Null;}
+ void SetNull(bool b) {Null = b;}
+ bool GetNullable(void) {return Nullable;}
+ void SetNullable(bool b) {Nullable = b;}
+ int GetType(void) {return Type;}
+ int GetClen(void) {return Clen;}
+ void SetGlobal(PGLOBAL g) {Global = g;}
+
+ // Methods
+ virtual bool SetValue_pval(PVAL valp, bool chktype = false) = 0;
+ virtual bool SetValue_char(char *p, int n) = 0;
+ virtual void SetValue_psz(PSZ s) = 0;
+ virtual void SetValue_bool(bool b) {assert(FALSE);}
+ virtual int CompareValue(PVAL vp) = 0;
+ virtual BYTE TestValue(PVAL vp);
+ virtual void SetValue(char c) {assert(false);}
+ virtual void SetValue(uchar c) {assert(false);}
+ virtual void SetValue(short i) {assert(false);}
+ virtual void SetValue(ushort i) {assert(false);}
+ virtual void SetValue(int n) {assert(false);}
+ virtual void SetValue(uint n) {assert(false);}
+ virtual void SetValue(longlong n) {assert(false);}
+ virtual void SetValue(ulonglong n) {assert(false);}
+ virtual void SetValue(double f) {assert(false);}
+ virtual void SetValue_pvblk(PVBLK blk, int n) = 0;
+ virtual void SetBinValue(void *p) = 0;
+ virtual bool GetBinValue(void *buf, int buflen, bool go) = 0;
+ virtual char *ShowValue(char *buf, int len = 0) = 0;
+ virtual char *GetCharString(char *p) = 0;
+ virtual bool IsEqual(PVAL vp, bool chktype) = 0;
+ virtual bool FormatValue(PVAL vp, char *fmt) = 0;
+
+ protected:
+ virtual bool SetConstFormat(PGLOBAL, FORMAT&) = 0;
+ const char *GetXfmt(void);
+
+ // Constructor used by derived classes
+ VALUE(int type, bool un = false);
+
+ // Members
+ PGLOBAL Global; // To reduce arglist
+ const char *Fmt;
+ const char *Xfmt;
+ bool Nullable; // True if value can be null
+ bool Null; // True if value is null
+ bool Unsigned; // True if unsigned
+ int Type; // The value type
+ int Clen; // Internal value length
+ int Prec;
+ }; // end of class VALUE
+
+/***********************************************************************/
+/* Class TYPVAL: represents a typed value. */
+/***********************************************************************/
+template <class TYPE>
+class DllExport TYPVAL : public VALUE {
+ public:
+ // Constructor
+ TYPVAL(TYPE n, int type, int prec = 0, bool un = false);
+
+ // Implementation
+ virtual bool IsTypeNum(void) {return true;}
+ virtual bool IsZero(void) {return Tval == 0;}
+ virtual void Reset(void) {Tval = 0;}
+ virtual int GetValLen(void);
+ virtual int GetValPrec() {return 0;}
+ virtual int GetSize(void) {return sizeof(TYPE);}
+ virtual PSZ GetCharValue(void) {return VALUE::GetCharValue();}
+ virtual char GetTinyValue(void) {return (char)Tval;}
+ virtual uchar GetUTinyValue(void) {return (uchar)Tval;}
+ virtual short GetShortValue(void) {return (short)Tval;}
+ virtual ushort GetUShortValue(void) {return (ushort)Tval;}
+ virtual int GetIntValue(void) {return (int)Tval;}
+ virtual uint GetUIntValue(void) {return (uint)Tval;}
+ virtual longlong GetBigintValue(void) {return (longlong)Tval;}
+ virtual ulonglong GetUBigintValue(void) {return (ulonglong)Tval;}
+ virtual double GetFloatValue(void) {return (double)Tval;}
+ virtual void *GetTo_Val(void) {return &Tval;}
+
+ // Methods
+ virtual bool SetValue_pval(PVAL valp, bool chktype);
+ virtual bool SetValue_char(char *p, int n);
+ virtual void SetValue_psz(PSZ s);
+ virtual void SetValue_bool(bool b) {Tval = (b) ? 1 : 0;}
+ virtual int CompareValue(PVAL vp);
+ virtual void SetValue(char c) {Tval = (TYPE)c; Null = false;}
+ virtual void SetValue(uchar c) {Tval = (TYPE)c; Null = false;}
+ virtual void SetValue(short i) {Tval = (TYPE)i; Null = false;}
+ virtual void SetValue(ushort i) {Tval = (TYPE)i; Null = false;}
+ virtual void SetValue(int n) {Tval = (TYPE)n; Null = false;}
+ virtual void SetValue(uint n) {Tval = (TYPE)n; Null = false;}
+ virtual void SetValue(longlong n) {Tval = (TYPE)n; Null = false;}
+ virtual void SetValue(ulonglong n) {Tval = (TYPE)n; Null = false;}
+ virtual void SetValue(double f) {Tval = (TYPE)f; Null = false;}
+ virtual void SetValue_pvblk(PVBLK blk, int n);
+ virtual void SetBinValue(void *p);
+ virtual bool GetBinValue(void *buf, int buflen, bool go);
+ virtual char *ShowValue(char *buf, int);
+ virtual char *GetCharString(char *p);
+ virtual bool IsEqual(PVAL vp, bool chktype);
+ virtual bool SetConstFormat(PGLOBAL, FORMAT&);
+ virtual bool FormatValue(PVAL vp, char *fmt);
+ virtual void Print(PGLOBAL g, FILE *, uint);
+ virtual void Print(PGLOBAL g, char *, uint);
+
+ protected:
+ // Default constructor not to be used
+ TYPVAL(void) : VALUE(TYPE_ERROR) {}
+
+ // Specialized functions
+ static ulonglong MaxVal(void);
+ TYPE GetTypedValue(PVAL vp);
+ TYPE GetTypedValue(PVBLK blk, int n);
+// TYPE GetTypedValue(PSZ s);
+
+ // Members
+ TYPE Tval;
+ }; // end of class TYPVAL
+
+/***********************************************************************/
+/* Specific STRING class. */
+/***********************************************************************/
+template <>
+class DllExport TYPVAL<PSZ>: public VALUE {
+ public:
+ // Constructors
+ TYPVAL(PSZ s);
+ TYPVAL(PGLOBAL g, PSZ s, int n, int c);
+
+ // Implementation
+ virtual bool IsTypeNum(void) {return false;}
+ virtual bool IsZero(void) {return *Strp == 0;}
+ virtual void Reset(void) {*Strp = 0;}
+ virtual int GetValLen(void) {return Len;};
+ virtual int GetValPrec() {return (Ci) ? 1 : 0;}
+ virtual int GetSize(void) {return (Strp) ? strlen(Strp) : 0;}
+ virtual PSZ GetCharValue(void) {return Strp;}
+ virtual char GetTinyValue(void);
+ virtual uchar GetUTinyValue(void);
+ virtual short GetShortValue(void);
+ virtual ushort GetUShortValue(void);
+ virtual int GetIntValue(void);
+ virtual uint GetUIntValue(void);
+ virtual longlong GetBigintValue(void);
+ virtual ulonglong GetUBigintValue(void);
+ virtual double GetFloatValue(void) {return atof(Strp);}
+ virtual void *GetTo_Val(void) {return Strp;}
+ virtual void SetPrec(int prec) {Ci = prec != 0;}
+
+ // Methods
+ virtual bool SetValue_pval(PVAL valp, bool chktype);
+ virtual bool SetValue_char(char *p, int n);
+ virtual void SetValue_psz(PSZ s);
+ virtual void SetValue_pvblk(PVBLK blk, int n);
+ virtual void SetValue(char c);
+ virtual void SetValue(uchar c);
+ virtual void SetValue(short i);
+ virtual void SetValue(ushort i);
+ virtual void SetValue(int n);
+ virtual void SetValue(uint n);
+ virtual void SetValue(longlong n);
+ virtual void SetValue(ulonglong n);
+ virtual void SetValue(double f);
+ virtual void SetBinValue(void *p);
+ virtual int CompareValue(PVAL vp);
+ virtual bool GetBinValue(void *buf, int buflen, bool go);
+ virtual char *ShowValue(char *buf, int);
+ virtual char *GetCharString(char *p);
+ virtual bool IsEqual(PVAL vp, bool chktype);
+ virtual bool FormatValue(PVAL vp, char *fmt);
+ virtual bool SetConstFormat(PGLOBAL, FORMAT&);
+
+ // Members
+ PSZ Strp;
+ bool Ci; // true if case insensitive
+ int Len;
+ }; // end of class TYPVAL<PSZ>
+
+/***********************************************************************/
+/* Specific DECIMAL class. */
+/***********************************************************************/
+class DllExport DECVAL: public TYPVAL<PSZ> {
+ public:
+ // Constructors
+ DECVAL(PSZ s);
+ DECVAL(PGLOBAL g, PSZ s, int n, int prec, bool uns);
+
+ // Implementation
+ virtual bool IsTypeNum(void) {return true;}
+ virtual bool IsZero(void);
+ virtual void Reset(void);
+ virtual int GetValPrec() {return Prec;}
+
+ // Methods
+ virtual bool GetBinValue(void *buf, int buflen, bool go);
+ virtual char *ShowValue(char *buf, int);
+ virtual bool IsEqual(PVAL vp, bool chktype);
+ virtual int CompareValue(PVAL vp);
+
+ // Members
+ }; // end of class DECVAL
+
+/***********************************************************************/
+/* Specific BINARY class. */
+/***********************************************************************/
+class DllExport BINVAL: public VALUE {
+ public:
+ // Constructors
+//BINVAL(void *p);
+ BINVAL(PGLOBAL g, void *p, int cl, int n);
+
+ // Implementation
+ virtual bool IsTypeNum(void) {return false;}
+ virtual bool IsZero(void);
+ virtual void Reset(void);
+ virtual int GetValLen(void) {return Clen;};
+ virtual int GetValPrec() {return 0;}
+ virtual int GetSize(void) {return Len;}
+ virtual PSZ GetCharValue(void) {return (PSZ)Binp;}
+ virtual char GetTinyValue(void);
+ virtual uchar GetUTinyValue(void);
+ virtual short GetShortValue(void);
+ virtual ushort GetUShortValue(void);
+ virtual int GetIntValue(void);
+ virtual uint GetUIntValue(void);
+ virtual longlong GetBigintValue(void);
+ virtual ulonglong GetUBigintValue(void);
+ virtual double GetFloatValue(void);
+ virtual void *GetTo_Val(void) {return Binp;}
+
+ // Methods
+ virtual bool SetValue_pval(PVAL valp, bool chktype);
+ virtual bool SetValue_char(char *p, int n);
+ virtual void SetValue_psz(PSZ s);
+ virtual void SetValue_pvblk(PVBLK blk, int n);
+ virtual void SetValue(char c);
+ virtual void SetValue(uchar c);
+ virtual void SetValue(short i);
+ virtual void SetValue(ushort i);
+ virtual void SetValue(int n);
+ virtual void SetValue(uint n);
+ virtual void SetValue(longlong n);
+ virtual void SetValue(ulonglong n);
+ virtual void SetValue(double f);
+ virtual void SetBinValue(void *p);
+ virtual bool GetBinValue(void *buf, int buflen, bool go);
+ virtual int CompareValue(PVAL vp) {assert(false); return 0;}
+ virtual char *ShowValue(char *buf, int);
+ virtual char *GetCharString(char *p);
+ virtual bool IsEqual(PVAL vp, bool chktype);
+ virtual bool FormatValue(PVAL vp, char *fmt);
+ virtual bool SetConstFormat(PGLOBAL, FORMAT&);
+
+ // Members
+ void *Binp;
+ char *Chrp;
+ int Len;
+ }; // end of class BINVAL
+
+/***********************************************************************/
+/* Class DTVAL: represents a time stamp value. */
+/***********************************************************************/
+class DllExport DTVAL : public TYPVAL<int> {
+ public:
+ // Constructors
+ DTVAL(PGLOBAL g, int n, int p, PSZ fmt);
+ DTVAL(PGLOBAL g, PSZ s, int n);
+ DTVAL(PGLOBAL g, short i);
+ DTVAL(PGLOBAL g, int n);
+ DTVAL(PGLOBAL g, longlong n);
+ DTVAL(PGLOBAL g, double f);
+
+ // Implementation
+ virtual bool SetValue_pval(PVAL valp, bool chktype);
+ virtual bool SetValue_char(char *p, int n);
+ virtual void SetValue_psz(PSZ s);
+ virtual void SetValue_pvblk(PVBLK blk, int n);
+ virtual char *GetCharString(char *p);
+ virtual char *ShowValue(char *buf, int);
+ virtual bool FormatValue(PVAL vp, char *fmt);
+ bool SetFormat(PGLOBAL g, PSZ fmt, int len, int year = 0);
+ bool SetFormat(PGLOBAL g, PVAL valp);
+ bool IsFormatted(void) {return Pdtp != NULL;}
+ bool MakeTime(struct tm *ptm);
+ static void SetTimeShift(void);
+ static int GetShift(void) {return Shift;}
+
+ // Methods
+ bool MakeDate(PGLOBAL g, int *val, int nval);
+
+ struct tm *GetGmTime(struct tm *);
+
+ protected:
+ // Default constructor not to be used
+ DTVAL(void) : TYPVAL<int>() {}
+
+ // Members
+ static int Shift; // Time zone shift in seconds
+ PDTP Pdtp; // To the DATPAR structure
+ char *Sdate; // Utility char buffer
+ int DefYear; // Used by ExtractDate
+ int Len; // Used by CHAR scalar function
+ }; // end of class DTVAL
+
+#endif // __VALUE__H__
diff --git a/storage/connect/xindex.cpp b/storage/connect/xindex.cpp
index caa7c667419..e36d958f28a 100755
--- a/storage/connect/xindex.cpp
+++ b/storage/connect/xindex.cpp
@@ -61,6 +61,9 @@
/***********************************************************************/
extern MBLOCK Nmblk; /* Used to initialize MBLOCK's */
extern "C" int trace;
+#if defined(XMAP)
+extern bool xmap;
+#endif // XMAP
/***********************************************************************/
/* Last two parameters are true to enable type checking, and last one */
@@ -810,12 +813,16 @@ bool XINDEX::SaveIndex(PGLOBAL g, PIXDEF sxp)
return rc;
} // end of SaveIndex
-#if !defined(XMAP)
/***********************************************************************/
/* Init: Open and Initialize a Key Index. */
/***********************************************************************/
bool XINDEX::Init(PGLOBAL g)
{
+#if defined(XMAP)
+ if (xmap)
+ return MapInit(g);
+#endif // XMAP
+
/*********************************************************************/
/* Table will be accessed through an index table. */
/* If sorting is required, this will be done later. */
@@ -1051,11 +1058,11 @@ err:
return true;
} // end of Init
-#else // XMAP
+#if defined(XMAP)
/***********************************************************************/
/* Init: Open and Initialize a Key Index. */
/***********************************************************************/
-bool XINDEX::Init(PGLOBAL g)
+bool XINDEX::MapInit(PGLOBAL g)
{
/*********************************************************************/
/* Table will be accessed through an index table. */
@@ -1256,7 +1263,7 @@ bool XINDEX::Init(PGLOBAL g)
err:
Close();
return true;
- } // end of Init
+ } // end of MapInit
#endif // XMAP
/***********************************************************************/
@@ -1564,6 +1571,46 @@ bool XINDEX::NextVal(bool eq)
} // end of NextVal
/***********************************************************************/
+/* XINDEX: Find Cur_K and Val_K's of previous index entry. */
+/* Returns false if Ok, true if there are no more values. */
+/***********************************************************************/
+bool XINDEX::PrevVal(void)
+ {
+ int n, neq = Nk + 1, curk;
+ PXCOL kcp;
+
+ if (Cur_K == 0)
+ return true;
+ else
+ curk = --Cur_K;
+
+ for (n = Nk, kcp = To_LastCol; kcp; n--, kcp = kcp->Previous) {
+ if (kcp->Kof) {
+ if (curk < kcp->Kof[kcp->Val_K])
+ neq = n;
+
+ } else {
+#ifdef _DEBUG
+ assert(curk == kcp->Val_K -1);
+#endif // _DEBUG
+ neq = n;
+ } // endif Kof
+
+#ifdef _DEBUG
+ assert(kcp->Val_K >= 0);
+#endif // _DEBUG
+
+ // If this is not a break...
+ if (neq > n)
+ break; // all previous columns have same value
+
+ curk = --kcp->Val_K; // This is a break, get new column value
+ } // endfor kcp
+
+ return false;
+ } // end of PrevVal
+
+/***********************************************************************/
/* XINDEX: Fetch a physical or logical record. */
/***********************************************************************/
int XINDEX::Fetch(PGLOBAL g)
@@ -1615,6 +1662,12 @@ int XINDEX::Fetch(PGLOBAL g)
Op = (Mul || Nval < Nk) ? OP_NXTDIF : OP_NEXT;
break;
+ case OP_LAST: // Read last key
+ for (Cur_K = Num_K - 1, kp = To_KeyCol; kp; kp = kp->Next)
+ kp->Val_K = kp->Kblp->GetNval() - 1;
+
+ Op = OP_NEXT;
+ break;
default: // Should be OP_EQ
// if (Tbxp->Key_Rank < 0) {
/***************************************************************/
@@ -1852,6 +1905,25 @@ int XINDXS::GroupSize(void)
} // end of GroupSize
/***********************************************************************/
+/* XINDXS: Find Cur_K and Val_K of previous index value. */
+/* Returns false if Ok, true if there are no more values. */
+/***********************************************************************/
+bool XINDXS::PrevVal(void)
+ {
+ if (--Cur_K < 0)
+ return true;
+
+ if (Mul) {
+ if (Cur_K < Pof[To_KeyCol->Val_K])
+ To_KeyCol->Val_K--;
+
+ } else
+ To_KeyCol->Val_K = Cur_K;
+
+ return false;
+ } // end of PrevVal
+
+/***********************************************************************/
/* XINDXS: Find Cur_K and Val_K of next index value. */
/* If b is true next value must be equal to last one. */
/* Returns false if Ok, true if there are no more (equal) values. */
@@ -1895,12 +1967,12 @@ int XINDXS::Fetch(PGLOBAL g)
/* Table read through a sorted index. */
/*********************************************************************/
switch (Op) {
- case OP_NEXT: // Read next
+ case OP_NEXT: // Read next
if (NextVal(false))
return -1; // End of indexed file
break;
- case OP_FIRST: // Read first
+ case OP_FIRST: // Read first
To_KeyCol->Val_K = Cur_K = 0;
Op = OP_NEXT;
break;
@@ -1914,7 +1986,7 @@ int XINDXS::Fetch(PGLOBAL g)
} // endif Mul
break;
- case OP_NXTDIF: // Read next dif
+ case OP_NXTDIF: // Read next dif
if (++To_KeyCol->Val_K == Ndif)
return -1; // End of indexed file
@@ -1924,7 +1996,17 @@ int XINDXS::Fetch(PGLOBAL g)
To_KeyCol->Val_K = Cur_K = 0;
Op = (Mul) ? OP_NXTDIF : OP_NEXT;
break;
- default: // Should OP_EQ
+ case OP_LAST: // Read first
+ Cur_K = Num_K - 1;
+ To_KeyCol->Val_K = Ndif - 1;
+ Op = OP_PREV;
+ break;
+ case OP_PREV: // Read previous
+ if (PrevVal())
+ return -1; // End of indexed file
+
+ break;
+ default: // Should be OP_EQ
/*****************************************************************/
/* Look for the first key equal to the link column values */
/* and return its rank whithin the index table. */
@@ -2837,7 +2919,8 @@ BYTE* KXYCOL::MapInit(PGLOBAL g, PCOL colp, int *n, BYTE *m)
} // endif n[1]
Ndf = n[0];
- IsSorted = colp->GetOpt() < 0;
+//IsSorted = colp->GetOpt() < 0;
+ IsSorted = false;
return m + Bkeys.Size + Keys.Size + Koff.Size;
} // end of MapInit
#endif // XMAP
diff --git a/storage/connect/xindex.h b/storage/connect/xindex.h
index ac886673b68..6ed0416bad5 100644
--- a/storage/connect/xindex.h
+++ b/storage/connect/xindex.h
@@ -192,9 +192,13 @@ class DllExport XXBASE : public CSORT, public BLOCK {
virtual void Print(PGLOBAL g, FILE *f, uint n);
virtual void Print(PGLOBAL g, char *ps, uint z);
virtual bool Init(PGLOBAL g) = 0;
+#if defined(XMAP)
+ virtual bool MapInit(PGLOBAL g) = 0;
+#endif // XMAP
virtual int MaxRange(void) {return 1;}
virtual int Fetch(PGLOBAL g) = 0;
virtual bool NextVal(bool eq) {return true;}
+ virtual bool PrevVal(void) {return true;}
virtual int FastFind(int nk) = 0;
virtual bool Reorder(PGLOBAL g) {return true;}
virtual int Range(PGLOBAL g, int limit = 0, bool incl = true)
@@ -206,22 +210,22 @@ class DllExport XXBASE : public CSORT, public BLOCK {
protected:
// Members
PTDBASE Tbxp; // Points to calling table TDB
- PXCOL To_KeyCol; // To KeyCol class list
+ PXCOL To_KeyCol; // To KeyCol class list
MBLOCK Record; // Record allocation block
int* &To_Rec; // We are using ftell, fseek
int Cur_K; // Index of current record
int Old_K; // Index of last record
int Num_K; // Size of Rec_K pointer array
- int Ndif; // Number of distinct values
+ int Ndif; // Number of distinct values
int Bot; // Bottom of research index
int Top; // Top of research index
int Inf, Sup; // Used for block optimization
- OPVAL Op; // Search operator
+ OPVAL Op; // Search operator
bool Mul; // true if multiple
bool Srtd; // true for sorted column
int Val_K; // Index of current value
- int Nblk; // Number of blocks
- int Sblk; // Block size
+ int Nblk; // Number of blocks
+ int Sblk; // Block size
int Thresh; // Thresh for sorting join indexes
int ID; // Index ID number
int Nth; // Nth constant to fetch
@@ -248,6 +252,9 @@ class DllExport XINDEX : public XXBASE {
// Methods
virtual void Reset(void);
virtual bool Init(PGLOBAL g);
+#if defined(XMAP)
+ virtual bool MapInit(PGLOBAL g);
+#endif // XMAP
virtual int Qcompare(int *, int *);
virtual int Fetch(PGLOBAL g);
virtual int FastFind(int nk);
@@ -257,6 +264,7 @@ class DllExport XINDEX : public XXBASE {
virtual int ColMaxSame(PXCOL kp);
virtual void Close(void);
virtual bool NextVal(bool eq);
+ virtual bool PrevVal(void);
virtual bool Make(PGLOBAL g, PIXDEF sxp);
virtual bool SaveIndex(PGLOBAL g, PIXDEF sxp);
virtual bool Reorder(PGLOBAL g);
@@ -296,6 +304,7 @@ class DllExport XINDXS : public XINDEX {
virtual int Fetch(PGLOBAL g);
virtual int FastFind(int nk);
virtual bool NextVal(bool eq);
+ virtual bool PrevVal(void);
virtual int Range(PGLOBAL g, int limit = 0, bool incl = true);
virtual int GroupSize(void);
@@ -403,6 +412,9 @@ class DllExport XXROW : public XXBASE {
// Methods
virtual bool Init(PGLOBAL g);
+#if defined(XMAP)
+ virtual bool MapInit(PGLOBAL g) {return true;}
+#endif // XMAP
virtual int Fetch(PGLOBAL g);
virtual int FastFind(int nk);
virtual int MaxRange(void) {return 1;}