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
This commit is contained in:
parent
2e175a4652
commit
37465ea2fe
@ -1930,7 +1930,11 @@ public:
|
||||
cached_table_flags= table_flags();
|
||||
}
|
||||
/* 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= '"';
|
||||
|
||||
if (!stricmp(ttp, "DBF") && fn) {
|
||||
char *length, *decimals, *nm;
|
||||
} 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
|
||||
|
||||
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;
|
||||
|
||||
comment= thd->make_lex_string(NULL, "", 0, true);
|
||||
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"
|
||||
|
||||
/***********************************************************************/
|
||||
/* General DB routines. */
|
||||
/***********************************************************************/
|
||||
/**************************************************************************/
|
||||
/* 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;
|
||||
|
@ -1,13 +1,13 @@
|
||||
/************ Odbconn C++ Functions Source Code File (.CPP) ************/
|
||||
/* Name: ODBCONN.CPP Version 1.5 */
|
||||
/* Name: ODBCONN.CPP Version 1.6 */
|
||||
/* */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 1998-2012 */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 1998-2013 */
|
||||
/* */
|
||||
/* This file contains the ODBC connection classes functions. */
|
||||
/***********************************************************************/
|
||||
|
||||
/***********************************************************************/
|
||||
/* Include relevant MariaDB header file. */
|
||||
/* Include relevant MariaDB header file. */
|
||||
/***********************************************************************/
|
||||
#include "my_global.h"
|
||||
#if defined(WIN32)
|
||||
@ -73,74 +73,7 @@ extern "C" int GetRcString(int id, char *buf, int bufsize);
|
||||
/**************************************************************************/
|
||||
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
|
||||
bool blank = true, bool nonull = true);
|
||||
|
||||
/***********************************************************************/
|
||||
/* Allocate the structure used to refer to the result set. */
|
||||
@ -192,6 +125,141 @@ void ResetNullValues(CATPARM *cap)
|
||||
|
||||
} // end of ResetNullValues
|
||||
|
||||
/***********************************************************************/
|
||||
/* ODBCColumns: constructs the result blocks containing all columns */
|
||||
/* of an ODBC table that will be retrieved by GetData commands. */
|
||||
/* Note: The first two columns (Qualifier, Owner) are ignored. */
|
||||
/***********************************************************************/
|
||||
PQRYRES ODBCColumns(PGLOBAL g, ODBConn *op, char *dsn, char *table,
|
||||
char *colpat)
|
||||
{
|
||||
static int dbtype[] = {DB_CHAR, DB_CHAR,
|
||||
DB_CHAR, DB_SHORT, DB_CHAR,
|
||||
DB_INT, DB_INT, DB_SHORT,
|
||||
DB_SHORT, DB_SHORT, DB_CHAR};
|
||||
static int buftyp[] = {TYPE_STRING, TYPE_STRING,
|
||||
TYPE_STRING, TYPE_SHORT, TYPE_STRING,
|
||||
TYPE_INT, TYPE_INT, TYPE_SHORT,
|
||||
TYPE_SHORT, TYPE_SHORT, TYPE_STRING};
|
||||
static unsigned int length[] = {0, 0, 0, 6, 20, 10, 10, 6, 6, 6, 128};
|
||||
int n, ncol = 11;
|
||||
int maxres;
|
||||
PQRYRES qrp;
|
||||
CATPARM *cap;
|
||||
ODBConn *ocp = op;
|
||||
|
||||
if (!op) {
|
||||
/**********************************************************************/
|
||||
/* Open the connection with the ODBC data source. */
|
||||
/**********************************************************************/
|
||||
ocp = new(g) ODBConn(g, NULL);
|
||||
|
||||
if (ocp->Open(dsn, 2) < 1) // 2 is openReadOnly
|
||||
return NULL;
|
||||
|
||||
} // endif op
|
||||
|
||||
/************************************************************************/
|
||||
/* Do an evaluation of the result size. */
|
||||
/************************************************************************/
|
||||
n = ocp->GetMaxValue(SQL_MAX_COLUMNS_IN_TABLE);
|
||||
maxres = (n) ? (int)n : 250;
|
||||
n = ocp->GetMaxValue(SQL_MAX_USER_NAME_LEN);
|
||||
length[0] = (n) ? (n + 1) : 128;
|
||||
n = ocp->GetMaxValue(SQL_MAX_TABLE_NAME_LEN);
|
||||
length[1] = (n) ? (n + 1) : 128;
|
||||
n = ocp->GetMaxValue(SQL_MAX_COLUMN_NAME_LEN);
|
||||
length[2] = (n) ? (n + 1) : 128;
|
||||
|
||||
#ifdef DEBTRACE
|
||||
htrc("ODBCColumns: max=%d len=%d,%d,%d\n",
|
||||
maxres, length[0], length[1], length[2]);
|
||||
#endif
|
||||
|
||||
/************************************************************************/
|
||||
/* Allocate the structures used to refer to the result set. */
|
||||
/************************************************************************/
|
||||
qrp = PlgAllocResult(g, ncol, maxres, IDS_COLUMNS + 1,
|
||||
dbtype, buftyp, length);
|
||||
|
||||
#ifdef DEBTRACE
|
||||
htrc("Getting col results ncol=%d\n", qrp->Nbcol);
|
||||
#endif
|
||||
|
||||
cap = AllocCatInfo(g, CAT_COL, table, qrp);
|
||||
cap->Pat = (PUCHAR)colpat;
|
||||
|
||||
/************************************************************************/
|
||||
/* Now get the results into blocks. */
|
||||
/************************************************************************/
|
||||
if ((n = ocp->GetCatInfo(cap)) >= 0) {
|
||||
qrp->Nblin = n;
|
||||
ResetNullValues(cap);
|
||||
|
||||
#ifdef DEBTRACE
|
||||
htrc("Columns: NBCOL=%d NBLIN=%d\n", qrp->Nbcol, qrp->Nblin);
|
||||
#endif
|
||||
} else
|
||||
qrp = NULL;
|
||||
|
||||
/************************************************************************/
|
||||
/* Close any local connection. */
|
||||
/************************************************************************/
|
||||
if (!op)
|
||||
ocp->Close();
|
||||
|
||||
/************************************************************************/
|
||||
/* Return the result pointer for use by GetData routines. */
|
||||
/************************************************************************/
|
||||
return qrp;
|
||||
} // end of ODBCColumns
|
||||
|
||||
/**************************************************************************/
|
||||
/* MyODBCCols: returns column info as required by ha_connect::pre_create. */
|
||||
/**************************************************************************/
|
||||
PQRYRES MyODBCCols(PGLOBAL g, char *tab, char *dsn)
|
||||
{
|
||||
int n;
|
||||
PCOLRES crp;
|
||||
PQRYRES qrp;
|
||||
ODBConn *ocp = new(g) ODBConn(g, NULL);
|
||||
|
||||
/**********************************************************************/
|
||||
/* Open the connection with the ODBC data source. */
|
||||
/**********************************************************************/
|
||||
if (ocp->Open(dsn, 2) < 1) // 2 is openReadOnly
|
||||
return NULL;
|
||||
|
||||
/**********************************************************************/
|
||||
/* Get the information about the ODBC table columns. */
|
||||
/**********************************************************************/
|
||||
if ((qrp = ODBCColumns(g, ocp, dsn, tab, NULL)))
|
||||
dsn = ocp->GetConnect(); // Complete connect string
|
||||
else
|
||||
return NULL;
|
||||
|
||||
/************************************************************************/
|
||||
/* Close the local connection. */
|
||||
/************************************************************************/
|
||||
ocp->Close();
|
||||
|
||||
/************************************************************************/
|
||||
/* Keep only the info used by ha_connect::pre_create. */
|
||||
/************************************************************************/
|
||||
qrp->Colresp = qrp->Colresp->Next->Next; // Skip Owner and Table names
|
||||
crp = qrp->Colresp->Next; // DB type
|
||||
|
||||
// Types must be PLG types, not SQL types
|
||||
for (int i = 0; i < qrp->Nblin; i++)
|
||||
crp->Kdata->SetValue(TranslateSQLType(crp->Kdata->GetIntValue(i),0,n),i);
|
||||
|
||||
crp = crp->Next->Next->Next->Next; // Should be Radix
|
||||
crp->Next = crp->Next->Next->Next; // Should be Remark
|
||||
qrp->Nbcol = 7; // Was 11, skipped 4
|
||||
return qrp;
|
||||
} // end of MyODBCCols
|
||||
|
||||
#if 0 // Currently not used by CONNECT
|
||||
/***********************************************************************/
|
||||
/* ODBCTables: constructs the result blocks containing all tables in */
|
||||
/* an ODBC database that will be retrieved by GetData commands. */
|
||||
@ -273,95 +341,6 @@ PQRYRES ODBCTables(PGLOBAL g, ODBConn *op, char *dsn, char *tabpat,
|
||||
return qrp;
|
||||
} // end of ODBCTables
|
||||
|
||||
/***********************************************************************/
|
||||
/* ODBCColumns: constructs the result blocks containing all columns */
|
||||
/* of an ODBC table that will be retrieved by GetData commands. */
|
||||
/* Note: The first two columns (Qualifier, Owner) are ignored. */
|
||||
/***********************************************************************/
|
||||
PQRYRES ODBCColumns(PGLOBAL g, ODBConn *op, char *dsn, char *table,
|
||||
char *colpat)
|
||||
{
|
||||
static int dbtype[] = {DB_CHAR, DB_CHAR,
|
||||
DB_CHAR, DB_SHORT, DB_CHAR,
|
||||
DB_INT, DB_INT, DB_SHORT,
|
||||
DB_SHORT, DB_SHORT, DB_CHAR};
|
||||
static int buftyp[] = {TYPE_STRING, TYPE_STRING,
|
||||
TYPE_STRING, TYPE_SHORT, TYPE_STRING,
|
||||
TYPE_INT, TYPE_INT, TYPE_SHORT,
|
||||
TYPE_SHORT, TYPE_SHORT, TYPE_STRING};
|
||||
static unsigned int length[] = {0, 0, 0, 6, 20, 10, 10, 6, 6, 6, 128};
|
||||
int n, ncol = 11;
|
||||
int maxres;
|
||||
PQRYRES qrp;
|
||||
CATPARM *cap;
|
||||
ODBConn *ocp = op;
|
||||
|
||||
if (!op) {
|
||||
/**********************************************************************/
|
||||
/* Open the connection with the ODBC data source. */
|
||||
/**********************************************************************/
|
||||
ocp = new(g) ODBConn(g, NULL);
|
||||
|
||||
if (ocp->Open(dsn, 2) < 1) // 2 is openReadOnly
|
||||
return NULL;
|
||||
|
||||
} // endif op
|
||||
|
||||
/************************************************************************/
|
||||
/* Do an evaluation of the result size. */
|
||||
/************************************************************************/
|
||||
n = ocp->GetMaxValue(SQL_MAX_COLUMNS_IN_TABLE);
|
||||
maxres = (n) ? (int)n : 250;
|
||||
n = ocp->GetMaxValue(SQL_MAX_USER_NAME_LEN);
|
||||
length[0] = (n) ? (n + 1) : 128;
|
||||
n = ocp->GetMaxValue(SQL_MAX_TABLE_NAME_LEN);
|
||||
length[1] = (n) ? (n + 1) : 128;
|
||||
n = ocp->GetMaxValue(SQL_MAX_COLUMN_NAME_LEN);
|
||||
length[2] = (n) ? (n + 1) : 128;
|
||||
|
||||
#ifdef DEBTRACE
|
||||
htrc("ODBCColumns: max=%d len=%d,%d,%d\n",
|
||||
maxres, length[0], length[1], length[2]);
|
||||
#endif
|
||||
|
||||
/************************************************************************/
|
||||
/* Allocate the structures used to refer to the result set. */
|
||||
/************************************************************************/
|
||||
qrp = PlgAllocResult(g, ncol, maxres, IDS_COLUMNS + 1,
|
||||
dbtype, buftyp, length);
|
||||
|
||||
#ifdef DEBTRACE
|
||||
htrc("Getting col results ncol=%d\n", qrp->Nbcol);
|
||||
#endif
|
||||
|
||||
cap = AllocCatInfo(g, CAT_COL, table, qrp);
|
||||
cap->Pat = (PUCHAR)colpat;
|
||||
|
||||
/************************************************************************/
|
||||
/* Now get the results into blocks. */
|
||||
/************************************************************************/
|
||||
if ((n = ocp->GetCatInfo(cap)) >= 0) {
|
||||
qrp->Nblin = n;
|
||||
ResetNullValues(cap);
|
||||
|
||||
#ifdef DEBTRACE
|
||||
htrc("Columns: NBCOL=%d NBLIN=%d\n", qrp->Nbcol, qrp->Nblin);
|
||||
#endif
|
||||
} else
|
||||
qrp = NULL;
|
||||
|
||||
/************************************************************************/
|
||||
/* Close any local connection. */
|
||||
/************************************************************************/
|
||||
if (!op)
|
||||
ocp->Close();
|
||||
|
||||
/************************************************************************/
|
||||
/* Return the result pointer for use by GetData routines. */
|
||||
/************************************************************************/
|
||||
return qrp;
|
||||
} // end of ODBCColumns
|
||||
|
||||
/**************************************************************************/
|
||||
/* PrimaryKeys: constructs the result blocks containing all the */
|
||||
/* ODBC catalog information concerning primary keys. */
|
||||
@ -606,7 +585,7 @@ PQRYRES GetColumnInfo(PGLOBAL g, char*& dsn,
|
||||
|
||||
return qrpc;
|
||||
} // end of GetColumnInfo
|
||||
|
||||
#endif // 0
|
||||
|
||||
/***********************************************************************/
|
||||
/* Implementation of DBX class. */
|
||||
|
@ -56,7 +56,7 @@ enum XDBTYPE {DB_ERROR = 0, /* Unknown or wrong type */
|
||||
DB_STRING = 1, /* Null terminated string */
|
||||
DB_CHAR = 2, /* Character array */
|
||||
DB_SHORT = 3, /* Used by some catalog functions */
|
||||
DB_INT = 4, /* Long integer array */
|
||||
DB_INT = 4, /* Long integer array */
|
||||
DB_DOUBLE = 5, /* Double float array */
|
||||
DB_DATE = 6}; /* Datetime value array */
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
/************* TabFmt C++ Program Source Code File (.CPP) **************/
|
||||
/* PROGRAM NAME: TABFMT */
|
||||
/* ------------- */
|
||||
/* Version 3.6 */
|
||||
/* Version 3.7 */
|
||||
/* */
|
||||
/* COPYRIGHT: */
|
||||
/* ---------- */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 2001 - 2012 */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 2001 - 2013 */
|
||||
/* */
|
||||
/* WHAT THIS PROGRAM DOES: */
|
||||
/* ----------------------- */
|
||||
@ -74,6 +74,300 @@ extern "C" int trace;
|
||||
PQRYRES PlgAllocResult(PGLOBAL, int, int, int, int *, int *,
|
||||
unsigned int *, bool blank = true, bool nonull = false);
|
||||
|
||||
/***********************************************************************/
|
||||
/* CSVColumns: constructs the result blocks containing the description */
|
||||
/* of all the columns of a CSV file that will be retrieved by #GetData.*/
|
||||
/* Note: the algorithm to set the type is based on the internal values */
|
||||
/* of types (TYPE_STRING < TYPE_FLOAT < TYPE_INT) (1 < 2 < 7). */
|
||||
/* If these values are changed, this will have to be revisited. */
|
||||
/***********************************************************************/
|
||||
PQRYRES CSVColumns(PGLOBAL g, char *fn, char sep, char q, int hdr, int mxr)
|
||||
{
|
||||
static int dbtype[] = {DB_CHAR, DB_SHORT, DB_CHAR,
|
||||
DB_INT, DB_INT, DB_SHORT};
|
||||
static int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING,
|
||||
TYPE_INT, TYPE_INT, TYPE_SHORT};
|
||||
static unsigned int length[] = {6, 6, 8, 10, 10, 6};
|
||||
char *p, *colname[MAXCOL], dechar, filename[_MAX_PATH], buf[4096];
|
||||
int i, imax, hmax, n, nerr, phase, blank, digit, dec, type;
|
||||
int ncol = sizeof(dbtype) / sizeof(int);
|
||||
int num_read = 0, num_max = 10000000; // Statistics
|
||||
int len[MAXCOL], typ[MAXCOL], prc[MAXCOL];
|
||||
FILE *infile;
|
||||
PQRYRES qrp;
|
||||
PCOLRES crp;
|
||||
|
||||
// num_max = atoi(p+1); // Max num of record to test
|
||||
#if defined(WIN32)
|
||||
if (strnicmp(setlocale(LC_NUMERIC, NULL), "French", 6))
|
||||
dechar = '.';
|
||||
else
|
||||
dechar = ',';
|
||||
#else // !WIN32
|
||||
dechar = '.';
|
||||
#endif // !WIN32
|
||||
|
||||
if (trace)
|
||||
htrc("File %s sep=%c q=%c hdr=%d mxr=%d\n",
|
||||
SVP(fn), sep, q, hdr, mxr);
|
||||
|
||||
if (!fn) {
|
||||
strcpy(g->Message, MSG(MISSING_FNAME));
|
||||
return NULL;
|
||||
} // endif fn
|
||||
|
||||
imax = hmax = nerr = 0;
|
||||
mxr = max(0, mxr);
|
||||
|
||||
for (i = 0; i < MAXCOL; i++) {
|
||||
colname[i] = NULL;
|
||||
len[i] = 0;
|
||||
typ[i] = TYPE_UNKNOWN;
|
||||
prc[i] = 0;
|
||||
} // endfor i
|
||||
|
||||
/*********************************************************************/
|
||||
/* Open the input file. */
|
||||
/*********************************************************************/
|
||||
PlugSetPath(filename, fn, PlgGetDataPath(g));
|
||||
|
||||
if (!(infile = fopen(filename, "r"))) {
|
||||
sprintf(g->Message, MSG(CANNOT_OPEN), filename);
|
||||
return NULL;
|
||||
} // endif infile
|
||||
|
||||
if (hdr) {
|
||||
/*******************************************************************/
|
||||
/* Make the column names from the first line. */
|
||||
/*******************************************************************/
|
||||
phase = 0;
|
||||
|
||||
if (fgets(buf, sizeof(buf), infile)) {
|
||||
n = strlen(buf) + 1;
|
||||
buf[n - 2] = '\0';
|
||||
p = (char*)PlugSubAlloc(g, NULL, n);
|
||||
memcpy(p, buf, n);
|
||||
|
||||
//skip leading blanks
|
||||
for (; *p == ' '; p++) ;
|
||||
|
||||
if (q && *p == q) {
|
||||
// Header is quoted
|
||||
p++;
|
||||
phase = 1;
|
||||
} // endif q
|
||||
|
||||
colname[0] = p;
|
||||
} else {
|
||||
sprintf(g->Message, MSG(FILE_IS_EMPTY), fn);
|
||||
goto err;
|
||||
} // endif's
|
||||
|
||||
for (i = 1; *p; p++)
|
||||
if (phase == 1 && *p == q) {
|
||||
*p = '\0';
|
||||
phase = 0;
|
||||
} else if (*p == sep && !phase) {
|
||||
*p = '\0';
|
||||
|
||||
//skip leading blanks
|
||||
for (; *(p+1) == ' '; p++) ;
|
||||
|
||||
if (q && *(p+1) == q) {
|
||||
// Header is quoted
|
||||
p++;
|
||||
phase = 1;
|
||||
} // endif q
|
||||
|
||||
colname[i++] = p + 1;
|
||||
} // endif sep
|
||||
|
||||
num_read++;
|
||||
imax = hmax = i;
|
||||
|
||||
for (i = 0; i < hmax; i++)
|
||||
length[0] = max(length[0], strlen(colname[i]));
|
||||
|
||||
} // endif hdr
|
||||
|
||||
for (num_read++; num_read <= num_max; num_read++) {
|
||||
/*******************************************************************/
|
||||
/* Now start the reading process. Read one line. */
|
||||
/*******************************************************************/
|
||||
if (fgets(buf, sizeof(buf), infile)) {
|
||||
buf[strlen(buf) - 1] = '\0';
|
||||
} else if (feof(infile)) {
|
||||
sprintf(g->Message, MSG(EOF_AFTER_LINE), num_read -1);
|
||||
break;
|
||||
} else {
|
||||
sprintf(g->Message, MSG(ERR_READING_REC), num_read, fn);
|
||||
goto err;
|
||||
} // endif's
|
||||
|
||||
/*******************************************************************/
|
||||
/* Make the test for field lengths. */
|
||||
/*******************************************************************/
|
||||
i = n = phase = blank = digit = dec = 0;
|
||||
|
||||
for (p = buf; *p; p++)
|
||||
if (*p == sep) {
|
||||
if (phase != 1) {
|
||||
if (i == MAXCOL - 1) {
|
||||
sprintf(g->Message, MSG(TOO_MANY_FIELDS), num_read, fn);
|
||||
goto err;
|
||||
} // endif i
|
||||
|
||||
if (n) {
|
||||
len[i] = max(len[i], n);
|
||||
type = (digit || (dec && n == 1)) ? TYPE_STRING
|
||||
: (dec) ? TYPE_FLOAT : TYPE_INT;
|
||||
typ[i] = min(type, typ[i]);
|
||||
prc[i] = max((typ[i] == TYPE_FLOAT) ? (dec - 1) : 0, prc[i]);
|
||||
} // endif n
|
||||
|
||||
i++;
|
||||
n = phase = blank = digit = dec = 0;
|
||||
} else // phase == 1
|
||||
n++;
|
||||
|
||||
} else if (*p == ' ') {
|
||||
if (phase < 2)
|
||||
n++;
|
||||
|
||||
if (blank)
|
||||
digit = 1;
|
||||
|
||||
} else if (*p == q) {
|
||||
if (phase == 0) {
|
||||
if (blank)
|
||||
if (++nerr > mxr) {
|
||||
sprintf(g->Message, MSG(MISPLACED_QUOTE), num_read);
|
||||
goto err;
|
||||
} else
|
||||
goto skip;
|
||||
|
||||
n = 0;
|
||||
phase = digit = 1;
|
||||
} else if (phase == 1) {
|
||||
if (*(p+1) == q) {
|
||||
// This is currently not implemented for CSV tables
|
||||
// if (++nerr > mxr) {
|
||||
// sprintf(g->Message, MSG(QUOTE_IN_QUOTE), num_read);
|
||||
// goto err;
|
||||
// } else
|
||||
// goto skip;
|
||||
|
||||
p++;
|
||||
n++;
|
||||
} else
|
||||
phase = 2;
|
||||
|
||||
} else if (++nerr > mxr) { // phase == 2
|
||||
sprintf(g->Message, MSG(MISPLACED_QUOTE), num_read);
|
||||
goto err;
|
||||
} else
|
||||
goto skip;
|
||||
|
||||
} else {
|
||||
if (phase == 2)
|
||||
if (++nerr > mxr) {
|
||||
sprintf(g->Message, MSG(MISPLACED_QUOTE), num_read);
|
||||
goto err;
|
||||
} else
|
||||
goto skip;
|
||||
|
||||
// isdigit cannot be used here because of debug assert
|
||||
if (!strchr("0123456789", *p)) {
|
||||
if (!digit && *p == dechar)
|
||||
dec = 1; // Decimal point found
|
||||
else if (blank || !(*p == '-' || *p == '+'))
|
||||
digit = 1;
|
||||
|
||||
} else if (dec)
|
||||
dec++; // More decimals
|
||||
|
||||
n++;
|
||||
blank = 1;
|
||||
} // endif's *p
|
||||
|
||||
if (phase == 1)
|
||||
if (++nerr > mxr) {
|
||||
sprintf(g->Message, MSG(UNBALANCE_QUOTE), num_read);
|
||||
goto err;
|
||||
} else
|
||||
goto skip;
|
||||
|
||||
if (n) {
|
||||
len[i] = max(len[i], n);
|
||||
type = (digit || n == 0 || (dec && n == 1)) ? TYPE_STRING
|
||||
: (dec) ? TYPE_FLOAT : TYPE_INT;
|
||||
typ[i] = min(type, typ[i]);
|
||||
prc[i] = max((typ[i] == TYPE_FLOAT) ? (dec - 1) : 0, prc[i]);
|
||||
} // endif n
|
||||
|
||||
imax = max(imax, i+1);
|
||||
skip: ; // Skip erroneous line
|
||||
} // endfor num_read
|
||||
|
||||
if (trace) {
|
||||
htrc("imax=%d Lengths:", imax);
|
||||
|
||||
for (i = 0; i < imax; i++)
|
||||
htrc(" %d", len[i]);
|
||||
|
||||
htrc("\n");
|
||||
} // endif trace
|
||||
|
||||
fclose(infile);
|
||||
|
||||
if (trace)
|
||||
htrc("CSVColumns: imax=%d hmax=%d len=%d\n",
|
||||
imax, hmax, length[0]);
|
||||
|
||||
/*********************************************************************/
|
||||
/* Allocate the structures used to refer to the result set. */
|
||||
/*********************************************************************/
|
||||
qrp = PlgAllocResult(g, ncol, imax, IDS_COLUMNS + 3,
|
||||
dbtype, buftyp, length);
|
||||
qrp->Nblin = imax;
|
||||
|
||||
/*********************************************************************/
|
||||
/* Now get the results into blocks. */
|
||||
/*********************************************************************/
|
||||
for (i = 0; i < imax; i++) {
|
||||
if (i >= hmax) {
|
||||
sprintf(buf, "COL%.3d", i+1);
|
||||
p = buf;
|
||||
} else
|
||||
p = colname[i];
|
||||
|
||||
if (typ[i] == TYPE_UNKNOWN) // Void column
|
||||
typ[i] = TYPE_STRING;
|
||||
|
||||
crp = qrp->Colresp; // Column Name
|
||||
crp->Kdata->SetValue(p, i);
|
||||
crp = crp->Next; // Data Type
|
||||
crp->Kdata->SetValue(typ[i], i);
|
||||
crp = crp->Next; // Type Name
|
||||
crp->Kdata->SetValue(GetTypeName(typ[i]), i);
|
||||
crp = crp->Next; // Precision
|
||||
crp->Kdata->SetValue(len[i], i);
|
||||
crp = crp->Next; // Length
|
||||
crp->Kdata->SetValue(len[i], i);
|
||||
crp = crp->Next; // Scale (precision)
|
||||
crp->Kdata->SetValue(prc[i], i);
|
||||
} // endfor i
|
||||
|
||||
/*********************************************************************/
|
||||
/* Return the result pointer for use by GetData routines. */
|
||||
/*********************************************************************/
|
||||
return qrp;
|
||||
|
||||
err:
|
||||
fclose(infile);
|
||||
return NULL;
|
||||
} // end of CSVCColumns
|
||||
|
||||
/* --------------------------- Class CSVDEF -------------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
|
@ -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);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/***********************************************************************/
|
||||
/* TABWMI: Author Olivier Bertrand -- PlugDB -- 2012 */
|
||||
/* TABWMI: Author Olivier Bertrand -- PlugDB -- 2012 - 2013 */
|
||||
/* TABWMI: Virtual table to get WMI information. */
|
||||
/***********************************************************************/
|
||||
#if !defined(WIN32)
|
||||
@ -21,6 +21,319 @@
|
||||
#include "plgcnx.h" // For DB types
|
||||
#include "resource.h"
|
||||
|
||||
extern "C" int trace;
|
||||
|
||||
/**************************************************************************/
|
||||
/* 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);
|
||||
|
||||
/* ------------------- Functions WMI Column info --------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
/* Structure used by WMI column info functions. */
|
||||
/***********************************************************************/
|
||||
typedef struct _WMIutil {
|
||||
IWbemServices *Svc;
|
||||
IWbemClassObject *Cobj;
|
||||
} WMIUTIL, *PWMIUT;
|
||||
|
||||
/***********************************************************************/
|
||||
/* Initialize WMI operations. */
|
||||
/***********************************************************************/
|
||||
PWMIUT InitWMI(PGLOBAL g, char *nsp, char *classname)
|
||||
{
|
||||
IWbemLocator *loc;
|
||||
char *p;
|
||||
HRESULT res;
|
||||
PWMIUT wp = (PWMIUT)PlugSubAlloc(g, NULL, sizeof(WMIUTIL));
|
||||
|
||||
if (trace)
|
||||
htrc("WMIColumns class %s space %s\n", SVP(classname), SVP(nsp));
|
||||
|
||||
/*********************************************************************/
|
||||
/* Set default values for the namespace and class name. */
|
||||
/*********************************************************************/
|
||||
if (!nsp)
|
||||
nsp = "root\\cimv2";
|
||||
|
||||
if (!classname) {
|
||||
if (!stricmp(nsp, "root\\cimv2"))
|
||||
classname = "ComputerSystemProduct";
|
||||
else if (!stricmp(nsp, "root\\cli"))
|
||||
classname = "Msft_CliAlias";
|
||||
else {
|
||||
strcpy(g->Message, "Missing class name");
|
||||
return NULL;
|
||||
} // endif classname
|
||||
|
||||
} // endif classname
|
||||
|
||||
/*********************************************************************/
|
||||
/* Initialize WMI. */
|
||||
/*********************************************************************/
|
||||
//res = CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
||||
res = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
||||
|
||||
if (FAILED(res)) {
|
||||
sprintf(g->Message, "Failed to initialize COM library. "
|
||||
"Error code = %p", res);
|
||||
return NULL;
|
||||
} // endif res
|
||||
|
||||
#if 0 // irrelevant for a DLL
|
||||
res = CoInitializeSecurity(NULL, -1, NULL, NULL,
|
||||
RPC_C_AUTHN_LEVEL_CONNECT,
|
||||
RPC_C_IMP_LEVEL_IMPERSONATE,
|
||||
NULL, EOAC_NONE, NULL);
|
||||
|
||||
if (res != RPC_E_TOO_LATE && FAILED(res)) {
|
||||
sprintf(g->Message, "Failed to initialize security. "
|
||||
"Error code = %p", res);
|
||||
CoUninitialize();
|
||||
return NULL;
|
||||
} // endif Res
|
||||
#endif // 0
|
||||
|
||||
res = CoCreateInstance(CLSID_WbemLocator, NULL,
|
||||
CLSCTX_INPROC_SERVER, IID_IWbemLocator,
|
||||
(void**) &loc);
|
||||
if (FAILED(res)) {
|
||||
sprintf(g->Message, "Failed to create Locator. "
|
||||
"Error code = %p", res);
|
||||
CoUninitialize();
|
||||
return NULL;
|
||||
} // endif res
|
||||
|
||||
res = loc->ConnectServer(_bstr_t(nsp),
|
||||
NULL, NULL, NULL, 0, NULL, NULL, &wp->Svc);
|
||||
|
||||
if (FAILED(res)) {
|
||||
sprintf(g->Message, "Could not connect. Error code = %p", res);
|
||||
loc->Release();
|
||||
CoUninitialize();
|
||||
return NULL;
|
||||
} // endif res
|
||||
|
||||
loc->Release();
|
||||
|
||||
if (trace)
|
||||
htrc("Successfully connected to namespace.\n");
|
||||
|
||||
/*********************************************************************/
|
||||
/* Perform a full class object retrieval. */
|
||||
/*********************************************************************/
|
||||
p = (char*)PlugSubAlloc(g, NULL, strlen(classname) + 7);
|
||||
|
||||
if (strchr(classname, '_'))
|
||||
strcpy(p, classname);
|
||||
else
|
||||
strcat(strcpy(p, "Win32_"), classname);
|
||||
|
||||
res = wp->Svc->GetObject(bstr_t(p), 0, 0, &wp->Cobj, 0);
|
||||
|
||||
if (FAILED(res)) {
|
||||
sprintf(g->Message, "failed GetObject %s in %s\n", classname, nsp);
|
||||
wp->Svc->Release();
|
||||
wp->Svc = NULL; // MUST be set to NULL (why?)
|
||||
return NULL;
|
||||
} // endif res
|
||||
|
||||
return wp;
|
||||
} // end of InitWMI
|
||||
|
||||
/***********************************************************************/
|
||||
/* WMIColumns: constructs the result blocks containing the description */
|
||||
/* of all the columns of a WMI table of a specified class. */
|
||||
/***********************************************************************/
|
||||
PQRYRES WMIColumns(PGLOBAL g, char *nsp, char *classname, PWMIUT wp)
|
||||
{
|
||||
static int dbtype[] = {DB_CHAR, DB_SHORT, DB_CHAR,
|
||||
DB_INT, DB_INT, DB_SHORT};
|
||||
static int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING,
|
||||
TYPE_INT, TYPE_INT, TYPE_SHORT};
|
||||
static unsigned int len, length[] = {0, 6, 8, 10, 10, 6};
|
||||
int i = 0, n = 0, ncol = sizeof(dbtype) / sizeof(int);
|
||||
int lng, typ, prec;
|
||||
LONG low, upp;
|
||||
BOOL b1, b2 = TRUE;
|
||||
BSTR propname;
|
||||
VARIANT val;
|
||||
CIMTYPE type;
|
||||
HRESULT res;
|
||||
SAFEARRAY *prnlist = NULL;
|
||||
PQRYRES qrp = NULL;
|
||||
PCOLRES crp;
|
||||
|
||||
/*********************************************************************/
|
||||
/* Initialize WMI if not done yet. */
|
||||
/*********************************************************************/
|
||||
if ((b1 = !wp) && !(wp = InitWMI(g, nsp, classname)))
|
||||
return NULL;
|
||||
|
||||
/*********************************************************************/
|
||||
/* Get the number of properties to return. */
|
||||
/*********************************************************************/
|
||||
res = wp->Cobj->Get(bstr_t("__Property_Count"), 0, &val, NULL, NULL);
|
||||
|
||||
if (FAILED(res)) {
|
||||
sprintf(g->Message, "failed Get(__Property_Count) res=%d\n", res);
|
||||
goto err;
|
||||
} // endif res
|
||||
|
||||
if (!(n = val.lVal)) {
|
||||
sprintf(g->Message, "Class %s in %s has no properties\n",
|
||||
classname, nsp);
|
||||
goto err;
|
||||
} // endif res
|
||||
|
||||
/*********************************************************************/
|
||||
/* Get max property name length. */
|
||||
/*********************************************************************/
|
||||
res = wp->Cobj->GetNames(NULL,
|
||||
WBEM_FLAG_ALWAYS | WBEM_FLAG_NONSYSTEM_ONLY,
|
||||
NULL, &prnlist);
|
||||
|
||||
if (FAILED(res)) {
|
||||
sprintf(g->Message, "failed GetNames res=%d\n", res);
|
||||
goto err;
|
||||
} // endif res
|
||||
|
||||
res = SafeArrayGetLBound(prnlist, 1, &low);
|
||||
res = SafeArrayGetUBound(prnlist, 1, &upp);
|
||||
|
||||
for (long i = low; i <= upp; i++) {
|
||||
// Get this property name.
|
||||
res = SafeArrayGetElement(prnlist, &i, &propname);
|
||||
|
||||
if (FAILED(res)) {
|
||||
sprintf(g->Message, "failed GetArrayElement res=%d\n", res);
|
||||
goto err;
|
||||
} // endif res
|
||||
|
||||
len = (unsigned)SysStringLen(propname);
|
||||
length[0] = max(length[0], len);
|
||||
} // enfor i
|
||||
|
||||
res = SafeArrayDestroy(prnlist);
|
||||
|
||||
/*********************************************************************/
|
||||
/* Allocate the structures used to refer to the result set. */
|
||||
/*********************************************************************/
|
||||
qrp = PlgAllocResult(g, ncol, n, IDS_COLUMNS + 3,
|
||||
dbtype, buftyp, length);
|
||||
|
||||
/*********************************************************************/
|
||||
/* Now get the results into blocks. */
|
||||
/*********************************************************************/
|
||||
res = wp->Cobj->BeginEnumeration(WBEM_FLAG_NONSYSTEM_ONLY);
|
||||
|
||||
if (FAILED(res)) {
|
||||
sprintf(g->Message, "failed BeginEnumeration hr=%d\n", res);
|
||||
qrp = NULL;
|
||||
goto err;
|
||||
} // endif hr
|
||||
|
||||
while (TRUE) {
|
||||
res = wp->Cobj->Next(0, &propname, &val, &type, NULL);
|
||||
|
||||
if (FAILED(res)) {
|
||||
sprintf(g->Message, "failed getting Next hr=%d\n", res);
|
||||
qrp = NULL;
|
||||
goto err;
|
||||
} else if (res == WBEM_S_NO_MORE_DATA) {
|
||||
VariantClear(&val);
|
||||
break;
|
||||
} // endif res
|
||||
|
||||
if (i >= n)
|
||||
break; // Should never happen
|
||||
else
|
||||
prec = 0;
|
||||
|
||||
switch (type) {
|
||||
case CIM_STRING:
|
||||
typ = TYPE_STRING;
|
||||
lng = 255;
|
||||
prec = 1; // Case insensitive
|
||||
break;
|
||||
case CIM_SINT32:
|
||||
case CIM_UINT32:
|
||||
case CIM_BOOLEAN:
|
||||
typ = TYPE_INT;
|
||||
lng = 9;
|
||||
break;
|
||||
case CIM_SINT8:
|
||||
case CIM_UINT8:
|
||||
case CIM_SINT16:
|
||||
case CIM_UINT16:
|
||||
typ = TYPE_SHORT;
|
||||
lng = 6;
|
||||
break;
|
||||
case CIM_REAL64:
|
||||
case CIM_REAL32:
|
||||
prec = 2;
|
||||
case CIM_SINT64:
|
||||
case CIM_UINT64:
|
||||
typ = TYPE_FLOAT;
|
||||
lng = 15;
|
||||
break;
|
||||
case CIM_DATETIME:
|
||||
typ = TYPE_DATE;
|
||||
lng = 19;
|
||||
break;
|
||||
case CIM_CHAR16:
|
||||
typ = TYPE_STRING;
|
||||
lng = 16;
|
||||
break;
|
||||
case CIM_EMPTY:
|
||||
typ = TYPE_STRING;
|
||||
lng = 24; // ???
|
||||
break;
|
||||
default:
|
||||
qrp->BadLines++;
|
||||
goto suite;
|
||||
} // endswitch type
|
||||
|
||||
crp = qrp->Colresp; // Column Name
|
||||
crp->Kdata->SetValue(_com_util::ConvertBSTRToString(propname), i);
|
||||
crp = crp->Next; // Data Type
|
||||
crp->Kdata->SetValue(typ, i);
|
||||
crp = crp->Next; // Type Name
|
||||
crp->Kdata->SetValue(GetTypeName(typ), i);
|
||||
crp = crp->Next; // Precision
|
||||
crp->Kdata->SetValue(lng, i);
|
||||
crp = crp->Next; // Length
|
||||
crp->Kdata->SetValue(lng, i);
|
||||
crp = crp->Next; // Scale (precision)
|
||||
crp->Kdata->SetValue(prec, i);
|
||||
i++;
|
||||
|
||||
suite:
|
||||
SysFreeString(propname);
|
||||
VariantClear(&val);
|
||||
} // endfor i
|
||||
|
||||
qrp->Nblin = i;
|
||||
b2 = b1;
|
||||
|
||||
err:
|
||||
if (b2) {
|
||||
// Cleanup
|
||||
wp->Cobj->Release();
|
||||
wp->Svc->Release();
|
||||
wp->Svc = NULL; // MUST be set to NULL (why?)
|
||||
CoUninitialize();
|
||||
} // endif b
|
||||
|
||||
/*********************************************************************/
|
||||
/* Return the result pointer for use by GetData routines. */
|
||||
/*********************************************************************/
|
||||
return qrp;
|
||||
} // end of WMIColumns
|
||||
|
||||
/* -------------- Implementation of the WMI classes ------------------ */
|
||||
|
||||
/***********************************************************************/
|
||||
|
Loading…
x
Reference in New Issue
Block a user