Commit 37465ea2 authored by Alexander Barkov's avatar Alexander Barkov

Adding an Olivier's changeset:

pre_create function and one is now able to create table
without giving the column specifications for tables of types:
DBF, ODBC, MYSQL, CSV, and WMI (on Windows)

modified:
  sql/handler.h
  sql/sql_table.cc
  storage/connect/ha_connect.cc
  storage/connect/ha_connect.h
  storage/connect/mycat.cc
  storage/connect/odbconn.cpp
  storage/connect/plgcnx.h
  storage/connect/tabfmt.cpp
  storage/connect/tabmysql.cpp
  storage/connect/tabwmi.cpp
parent 2e175a46
......@@ -1931,6 +1931,10 @@ public:
}
/* ha_ methods: pubilc wrappers for private virtual API */
/* Added by O. Bertrand */
virtual bool pre_create(THD *thd, void *crt_info, void *alt_info)
{return true;}
int ha_open(TABLE *table, const char *name, int mode, uint test_if_locked);
int ha_index_init(uint idx, bool sorted)
{
......
......@@ -4135,12 +4135,6 @@ bool mysql_create_table_no_lock(THD *thd,
/* Check for duplicate fields and check type of table to create */
if (!alter_info->create_list.elements)
{
my_message(ER_TABLE_MUST_HAVE_COLUMNS, ER(ER_TABLE_MUST_HAVE_COLUMNS),
MYF(0));
DBUG_RETURN(TRUE);
}
if (check_engine(thd, db, table_name, create_info))
DBUG_RETURN(TRUE);
......@@ -4320,6 +4314,14 @@ bool mysql_create_table_no_lock(THD *thd,
}
#endif
// Added by O. Bertrand
if (!alter_info->create_list.elements &&
file->pre_create(thd, create_info, alter_info))
{
my_message(ER_TABLE_MUST_HAVE_COLUMNS, ER(ER_TABLE_MUST_HAVE_COLUMNS),
MYF(0));
DBUG_RETURN(TRUE);
}
if (mysql_prepare_create_table(thd, create_info, alter_info,
internal_tmp_table,
&db_options, file,
......
......@@ -126,6 +126,9 @@
#define my_strlwr(p) my_casedn_str(default_charset_info, (p));
#define my_stricmp(a, b) my_strcasecmp(default_charset_info, (a), (b))
#if defined (WIN32)
typedef struct _WMIutil *PWMIUT; /* Used to call WMIColumns */
#endif
/****************************************************************************/
/* CONNECT functions called externally. */
/****************************************************************************/
......@@ -152,6 +155,14 @@ void XmlCleanupParserLib(void);
/* Functions called externally by pre_parser. */
/****************************************************************************/
PQRYRES DBFColumns(PGLOBAL g, char *fn, BOOL info);
PQRYRES MyODBCCols(PGLOBAL g, char *tab, char *dsn);
PQRYRES CSVColumns(PGLOBAL g, char *fn, char sep, char q, int hdr, int mxr);
PQRYRES MyColumns(PGLOBAL g, char *host, char *db, char *user, char *pwd,
char *table, char *colpat, int port, bool key);
#if defined(WIN32)
PQRYRES WMIColumns(PGLOBAL g, char *nsp, char *classname, PWMIUT wp= NULL);
#endif // WIN32
char GetTypeID(char *type);
enum enum_field_types PLGtoMYSQL(int type, bool gdf);
bool check_string_char_length(LEX_STRING *str, const char *err_msg,
uint max_char_length, CHARSET_INFO *cs,
......@@ -388,17 +399,19 @@ static int connect_init_func(void *p)
static int connect_done_func(void *p)
{
int error= 0;
PCONNECT pc, pn;
DBUG_ENTER("connect_done_func");
if (connect_open_tables.records)
error= 1;
for (PCONNECT p= user_connect::to_users; p; p= p->next) {
if (p->g)
PlugCleanup(p->g, true);
for (pc= user_connect::to_users; pc; pc= pn) {
if (pc->g)
PlugCleanup(pc->g, true);
delete p;
} // endfor p
pn= pc->next;
delete pc;
} // endfor pc
my_hash_free(&connect_open_tables);
mysql_mutex_destroy(&connect_mutex);
......@@ -613,11 +626,11 @@ PGLOBAL ha_connect::GetPlug(THD *thd)
/****************************************************************************/
/* Return the value of an option specified in the option list. */
/****************************************************************************/
char *ha_connect::GetListOption(char *opname, const char *oplist)
char *ha_connect::GetListOption(char *opname, const char *oplist, char *def)
{
char key[16], val[256];
char *pk, *pv, *pn;
char *opval= NULL;
char *opval= def;
int n;
for (pk= (char*)oplist; ; pk= ++pn) {
......@@ -3244,26 +3257,99 @@ bool ha_connect::add_fields(THD *thd, void *alt_info,
@note
Not really implemented yet.
*/
bool ha_connect::pre_create(THD *thd, void *alter_info)
bool ha_connect::pre_create(THD *thd, void *crt_info, void *alt_info)
{
char *ttp= "DOS" , *fn= NULL;
char ttp= '?', spc= ',', qch= 0, *typn= "DOS";
char *fn, *dsn, *tab, *db, *host, *user, *pwd, *prt, *sep;
#if defined(WIN32)
char *nsp= NULL, *cls= NULL;
#endif // WIN32
int port= MYSQL_PORT, hdr= 0, mxr= 0;
bool ok= false;
LEX *lex= thd->lex;
HA_CREATE_INFO *create_info= (HA_CREATE_INFO *)crt_info;
engine_option_value *pov;
PQRYRES qrp;
PCOLRES crp;
PGLOBAL g= GetPlug(thd);
if (!g)
fn= dsn= tab= db= host= user= pwd= prt= sep= NULL;
if (g) {
// Set default values
tab= (char*)create_info->alias;
db= thd->db;
} else
return true;
for (pov= lex->create_info.option_list; pov; pov= pov->next)
if (!stricmp(pov->name.str, "table_type"))
ttp= pov->value.str;
else if (!stricmp(pov->name.str, "file_name"))
// Get the useful create options
for (pov= create_info->option_list; pov; pov= pov->next)
if (!stricmp(pov->name.str, "table_type")) {
typn= pov->value.str;
ttp= GetTypeID(typn);
} else if (!stricmp(pov->name.str, "file_name")) {
fn= pov->value.str;
} else if (!stricmp(pov->name.str, "tabname")) {
tab= pov->value.str;
} else if (!stricmp(pov->name.str, "db_name")) {
db= pov->value.str;
} else if (!stricmp(pov->name.str, "sep_char")) {
sep= pov->value.str;
spc= (!strcmp(sep, "\\t")) ? '\t' : *sep;
} else if (!stricmp(pov->name.str, "qchar")) {
qch= *pov->value.str;
} else if (!stricmp(pov->name.str, "quoted")) {
if (!qch)
qch= '"';
} else if (!stricmp(pov->name.str, "header")) {
hdr= atoi(pov->value.str);
} else if (!stricmp(pov->name.str, "option_list")) {
host= GetListOption("host", pov->value.str, "localhost");
user= GetListOption("user", pov->value.str, "root");
pwd= GetListOption("password", pov->value.str);
prt= GetListOption("port", pov->value.str);
port= (prt) ? atoi(prt) : MYSQL_PORT;
#if defined(WIN32)
nsp= GetListOption("namespace", pov->value.str);
cls= GetListOption("class", pov->value.str);
#endif
mxr= atoi(GetListOption("maxerr", pov->value.str, "0"));
} // endelse option_list
if (!stricmp(ttp, "DBF") && fn) {
char *length, *decimals, *nm;
switch (ttp) {
case 'O': // ODBC
if (!(dsn= create_info->connect_string.str))
sprintf(g->Message, "Missing %s connection string", typn);
else
ok= true;
break;
case 'A': // DBF
case 'C': // CSV
if (!fn)
sprintf(g->Message, "Missing %s file name", typn);
else
ok= true;
break;
case 'Y': // MYSQL
if (!user)
user= "root"; // Avoid crash
ok= true;
break;
#if defined(WIN32)
case 'W': // WMI
ok= true;
break;
#endif // WIN32
default:
sprintf(g->Message, "Cannot get column info for table type %s", typn);
} // endif ttp
if (ok) {
char *length, *decimals, *nm, *rem;
int i, len, dec;
bool b;
LEX_STRING *comment, *name;
......@@ -3274,13 +3360,32 @@ bool ha_connect::pre_create(THD *thd, void *alter_info)
if (cat)
cat->SetDataPath(g, thd->db);
else
return true;
return true; // Should never happen
if (!(qrp= DBFColumns(g, fn, false)))
return true;
switch (ttp) {
case 'A':
qrp= DBFColumns(g, fn, false);
break;
case 'O':
qrp= MyODBCCols(g, tab, dsn);
break;
case 'Y':
qrp= MyColumns(g, host, db, user, pwd, tab, NULL, port, false);
break;
case 'C':
qrp= CSVColumns(g, fn, spc, qch, hdr, mxr);
break;
#if defined(WIN32)
case 'W':
qrp= WMIColumns(g, nsp, cls);
break;
#endif // WIN32
} // endswitch ttp
comment= (LEX_STRING *)PlugSubAlloc(g, NULL, sizeof(LEX_STRING));
memset(comment, 0, sizeof(LEX_STRING));
if (!qrp) {
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0, g->Message);
return true;
} // endif qrp
for (i= 0; i < qrp->Nblin; i++) {
crp = qrp->Colresp; // Column Name
......@@ -3289,11 +3394,11 @@ bool ha_connect::pre_create(THD *thd, void *alter_info)
crp = crp->Next; // Data Type
type= PLGtoMYSQL(crp->Kdata->GetIntValue(i), true);
crp = crp->Next; // Type Name
crp = crp->Next; // Precision
crp = crp->Next; // Length
crp = crp->Next; // Precision (length)
len= crp->Kdata->GetIntValue(i);
length= (char*)PlugSubAlloc(g, NULL, 8);
sprintf(length, "%d", len);
crp = crp->Next; // Length
crp = crp->Next; // Scale (precision)
if ((dec= crp->Kdata->GetIntValue(i))) {
......@@ -3302,18 +3407,23 @@ bool ha_connect::pre_create(THD *thd, void *alter_info)
} else
decimals= NULL;
if ((crp= crp->Next) && // Remark (comment)
(rem= crp->Kdata->GetCharValue(i)))
comment= thd->make_lex_string(NULL, rem, strlen(rem), true);
else
comment= thd->make_lex_string(NULL, "", 0, true);
// Now add the field
// b= add_field_to_list(thd, &name, type, length, decimals,
// 0, NULL, NULL, comment, NULL, NULL, NULL, 0, NULL, NULL);
b= add_fields(thd, alter_info, name, type, length, decimals,
b= add_fields(thd, alt_info, name, type, length, decimals,
0, comment, NULL, NULL, NULL);
} // endfor i
return false;
} // endif ttp
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0, g->Message);
return true;
} // end of pre_create
......
......@@ -335,7 +335,7 @@ char *GetValStr(OPVAL vop, bool neg);
ha_rows records_in_range(uint inx, key_range *min_key,
key_range *max_key);
int delete_table(const char *from);
bool pre_create(THD *thd, void *alter_info);
bool pre_create(THD *thd, void *crt_info, void *alt_info);
int create(const char *name, TABLE *form,
HA_CREATE_INFO *create_info); ///< required
bool check_if_incompatible_data(HA_CREATE_INFO *info,
......@@ -346,7 +346,7 @@ char *GetValStr(OPVAL vop, bool neg);
int optimize(THD* thd, HA_CHECK_OPT* check_opt);
protected:
char *GetListOption(char *opname, const char *oplist);
char *GetListOption(char *opname, const char *oplist, char *def= NULL);
bool add_fields(THD *thd, void *alter_info,
LEX_STRING *field_name,
enum_field_types type,
......
......@@ -16,7 +16,9 @@
/*************** Mycat CC Program Source Code File (.CC) ***************/
/* PROGRAM NAME: MYCAT */
/* ------------- */
/* Version 1.2 */
/* Version 1.3 */
/* */
/* Author: Olivier Bertrand 2012 - 2013 */
/* */
/* WHAT THIS PROGRAM DOES: */
/* ----------------------- */
......@@ -84,16 +86,113 @@
#include "ha_connect.h"
#include "mycat.h"
/***********************************************************************/
/**************************************************************************/
/* Extern static variables. */
/**************************************************************************/
#if defined(WIN32)
extern "C" HINSTANCE s_hModule; // Saved module handle
#endif // !WIN32
extern int xtrace;
/**************************************************************************/
/* General DB routines. */
/***********************************************************************/
/**************************************************************************/
//bool PlugCheckPattern(PGLOBAL, LPCSTR, LPCSTR);
#if !defined(WIN32)
extern "C" int GetRcString(int id, char *buf, int bufsize);
#endif // !WIN32
//void ptrc(char const *fmt, ...);
extern int xtrace;
/**************************************************************************/
/* Allocate the result structure that will contain result data. */
/**************************************************************************/
PQRYRES PlgAllocResult(PGLOBAL g, int ncol, int maxres, int ids,
int *dbtype, int *buftyp, unsigned int *length,
bool blank = false, bool nonull = false)
{
char cname[NAM_LEN+1];
int i;
PCOLRES *pcrp, crp;
PQRYRES qrp;
/************************************************************************/
/* Allocate the structure used to contain the result set. */
/************************************************************************/
qrp = (PQRYRES)PlugSubAlloc(g, NULL, sizeof(QRYRES));
pcrp = &qrp->Colresp;
qrp->Continued = false;
qrp->Truncated = false;
qrp->Info = false;
qrp->Suball = true;
qrp->Maxres = maxres;
qrp->Maxsize = 0;
qrp->Nblin = 0;
qrp->Nbcol = 0; // will be ncol
qrp->Cursor = 0;
qrp->BadLines = 0;
for (i = 0; i < ncol; i++) {
*pcrp = (PCOLRES)PlugSubAlloc(g, NULL, sizeof(COLRES));
crp = *pcrp;
pcrp = &crp->Next;
crp->Colp = NULL;
crp->Ncol = ++qrp->Nbcol;
crp->Type = buftyp[i];
crp->Length = length[i];
crp->Clen = GetTypeSize(crp->Type, length[i]);
crp->Prec = 0;
crp->DBtype = dbtype[i];
if (ids > 0) {
#if defined(XMSG)
// Get header from message file
strncpy(cname, PlugReadMessage(g, ids + crp->Ncol, NULL), NAM_LEN);
cname[NAM_LEN] = 0; // for truncated long names
#elif defined(WIN32)
// Get header from ressource file
LoadString(s_hModule, ids + crp->Ncol, cname, sizeof(cname));
#else // !WIN32
GetRcString(ids + crp->Ncol, cname, sizeof(cname));
#endif // !WIN32
crp->Name = (PSZ)PlugSubAlloc(g, NULL, strlen(cname) + 1);
strcpy(crp->Name, cname);
} else
crp->Name = NULL; // Will be set by caller
// Allocate the Value Block that will contain data
if (crp->Length || nonull)
crp->Kdata = AllocValBlock(g, NULL, crp->Type, maxres,
crp->Length, 0, true, blank);
else
crp->Kdata = NULL;
if (g->Trace)
htrc("Column(%d) %s type=%d len=%d value=%p\n",
crp->Ncol, crp->Name, crp->Type, crp->Length, crp->Kdata);
} // endfor i
*pcrp = NULL;
return qrp;
} // end of PlgAllocResult
/***********************************************************************/
/* Get a unique char identifier for types. The letter used are: */
/* ABCDEF..I.KLM.O..R.T.VWXY.. */
/***********************************************************************/
char GetTypeID(char *type)
{
return (!type) ? 'D' // DOS (default)
: (!stricmp(type, "FMT")) ? 'T' // CSV
: (!stricmp(type, "DIR")) ? 'R' // diR
: (!stricmp(type, "DBF")) ? 'A' // dbAse
: (!stricmp(type, "SYS")) ? 'I' // INI
: (!stricmp(type, "TBL")) ? 'L' // tbL
: (!stricmp(type, "MYSQL")) ? 'Y' // mYsql
: (!stricmp(type, "OEM")) ? 'E' : toupper(*type);
} // end of GetTypeID
/* ------------------------- Class CATALOG --------------------------- */
......@@ -252,15 +351,8 @@ int MYCAT::GetColCatInfo(PGLOBAL g, PTABDEF defp)
PCOLDEF cdp, lcdp= NULL, tocols= NULL;
PCOLINFO pcf= (PCOLINFO)PlugSubAlloc(g, NULL, sizeof(COLINFO));
/*********************************************************************/
/* Get a unique char identifier for types. The letter used are: */
/* ABCDEF..IJKLM.OPQRSTUV.XYZ */
/*********************************************************************/
char tc= (!stricmp(type, "FMT")) ? 'T' // fmT
: (!stricmp(type, "DBF")) ? 'A' // dbAse
: (!stricmp(type, "TBL")) ? 'L' // tbL
: (!stricmp(type, "OEM")) ? 'E' // oEm
: (!stricmp(type, "DIR")) ? 'R' : toupper(*type);
// Get a unique char identifier for type
char tc= GetTypeID(type);
// Take care of the column definitions
i= poff= nof= nlg= 0;
......@@ -389,8 +481,8 @@ int MYCAT::GetColCatInfo(PGLOBAL g, PTABDEF defp)
case 'A':
recln= nlg;
break;
case 'C':
case 'T':
case 'C':
// The number of separators (assuming an extra one can exist)
// recln= poff * ((qotd) ? 3 : 1); to be investigated
recln= nlg + poff * 3; // To be safe
......@@ -467,6 +559,7 @@ PRELDEF MYCAT::GetTableDesc(PGLOBAL g, LPCSTR name,
/***********************************************************************/
PRELDEF MYCAT::MakeTableDesc(PGLOBAL g, LPCSTR name, LPCSTR am)
{
char tc;
PRELDEF tdp= NULL;
if (xtrace)
......@@ -476,17 +569,14 @@ PRELDEF MYCAT::MakeTableDesc(PGLOBAL g, LPCSTR name, LPCSTR am)
/* Get a unique char identifier for types. The letter used are: */
/* ABCDEF..IJKLM.OPQRSTUVWXYZ and Allocate table definition class */
/*********************************************************************/
switch ((!am) ? 'D' : (!stricmp(am, "FMT")) ? 'C' // CSV
: (!stricmp(am, "DIR")) ? 'R'
: (!stricmp(am, "SYS")) ? 'I' // INI
// : (!stricmp(am, "DUMMY")) ? 'U'
: (!stricmp(am, "TBL")) ? 'L'
// : (!stricmp(am, "PLG")) ? 'S' // Compatibility
: (!stricmp(am, "MYSQL")) ? 'Y' // mYsql
: (!stricmp(am, "OEM")) ? 'E' : toupper(*am)) {
tc= GetTypeID((char*)am);
switch (tc) {
case 'F':
case 'B':
case 'A':
case 'D': tdp= new(g) DOSDEF; break;
case 'T':
case 'C': tdp= new(g) CSVDEF; break;
case 'I': tdp= new(g) INIDEF; break;
case 'R': tdp= new(g) DIRDEF; break;
......
This diff is collapsed.
This diff is collapsed.
......@@ -67,7 +67,13 @@ void PrintResult(PGLOBAL, PSEM, PQRYRES);
extern "C" int trace;
#if 0
/**************************************************************************/
/* Allocate the result structure that will contain result data. */
/**************************************************************************/
PQRYRES PlgAllocResult(PGLOBAL g, int ncol, int maxres, int ids,
int *dbtype, int *buftyp, unsigned int *length,
bool blank = true, bool nonull = true);
/************************************************************************/
/* MyColumns: constructs the result blocks containing all columns */
/* of a MySQL table that will be retrieved by GetData commands. */
......@@ -152,8 +158,11 @@ PQRYRES MyColumns(PGLOBAL g, char *host, char *db, char *user, char *pwd,
} else
qrp->Nblin++;
if ((type = MYSQLtoPLG(cmd)) == TYPE_ERROR) {
sprintf(g->Message, "Unsupported column type %s", cmd);
return NULL;
} // endif type
type = MYSQLtoPLG(cmd);
crp = crp->Next;
crp->Kdata->SetValue(type, i);
crp = crp->Next;
......@@ -227,6 +236,7 @@ PQRYRES MyColumns(PGLOBAL g, char *host, char *db, char *user, char *pwd,
return qrp;
} // end of MyColumns
#if 0
/**************************************************************************/
/* SemMySQLColumns: analyze a MySQL table for column format. */
/**************************************************************************/
......@@ -327,7 +337,7 @@ bool MYSQLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
Database = Cat->GetStringCatInfo(g, Name, "Database", "*");
Tabname = Cat->GetStringCatInfo(g, Name, "Name", Name); // Deprecated
Tabname = Cat->GetStringCatInfo(g, Name, "Tabname", Tabname);
Username = Cat->GetStringCatInfo(g, Name, "User", NULL);
Username = Cat->GetStringCatInfo(g, Name, "User", "root");
Password = Cat->GetStringCatInfo(g, Name, "Password", NULL);
Portnumber = Cat->GetIntCatInfo(Name, "Port", MYSQL_PORT);
Bind = !!Cat->GetIntCatInfo(Name, "Bind", 0);
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment