Commit 7dc48ae3 authored by Alexander Barkov's avatar Alexander Barkov

Merge 10.0-connect -> 10.0

parents 9290a580 727c1f62
...@@ -5147,6 +5147,7 @@ char check_if_ignore_table(const char *table_name, char *table_type) ...@@ -5147,6 +5147,7 @@ char check_if_ignore_table(const char *table_name, char *table_type)
if (!opt_no_data && if (!opt_no_data &&
(!my_strcasecmp(&my_charset_latin1, table_type, "MRG_MyISAM") || (!my_strcasecmp(&my_charset_latin1, table_type, "MRG_MyISAM") ||
!strcmp(table_type,"MRG_ISAM") || !strcmp(table_type,"MRG_ISAM") ||
!strcmp(table_type,"CONNECT") ||
!strcmp(table_type,"FEDERATED"))) !strcmp(table_type,"FEDERATED")))
result= IGNORE_DATA; result= IGNORE_DATA;
} }
......
...@@ -379,6 +379,7 @@ sub main { ...@@ -379,6 +379,7 @@ sub main {
mtr_report("Logging: $0 ", join(" ", @ARGV)); mtr_report("Logging: $0 ", join(" ", @ARGV));
$DEFAULT_SUITES.= ',' . join(',', qw( $DEFAULT_SUITES.= ',' . join(',', qw(
connect
query_response_time query_response_time
sequence sequence
spider spider
......
...@@ -1117,3 +1117,95 @@ ...@@ -1117,3 +1117,95 @@
fun:_nss_dns_gethostbyaddr_r fun:_nss_dns_gethostbyaddr_r
fun:gethostbyaddr_r fun:gethostbyaddr_r
} }
{
ConnectSE: unixODBC SQLAllocEnv leaves some "still reachable" pointers
Memcheck:Leak
fun:malloc
fun:strdup
...
obj:*/libodbc.so*
fun:_ZN7ODBConn10GetDriversEP7_qryres
}
{
ConnectSE: unixODBC SQLAllocEnv leaves some "still reachable" pointers
Memcheck:Leak
fun:calloc
...
obj:*/libodbc.so*
fun:_ZN7ODBConn10GetDriversEP7_qryres
}
{
ConnectSE: unixODBC SQLAllocEnv leavs some "still reachable" pointers
Memcheck:Leak
fun:malloc
fun:strdup
...
obj:*/libodbc.so*
fun:_ZN7ODBConn14GetDataSourcesEP7_qryres
}
{
ConnectSE: unixODBC SQLAllocEnv leavs some "still reachable" pointers
Memcheck:Leak
fun:calloc
...
obj:*/libodbc.so*
fun:_ZN7ODBConn14GetDataSourcesEP7_qryres
}
{
ConnectSE: unixODBC SQLDriverConnect leaves some "still reachable" pointers
Memcheck:Leak
fun:malloc
fun:strdup
...
obj:*/libodbc.so*
fun:SQLDriverConnect
fun:_ZN7ODBConn7ConnectEj
fun:_ZN7ODBConn4OpenEPcj
fun:_Z11ODBCColumnsP7_globalPcS1_S1_b
fun:_ZL26connect_assisted_discoveryP10handlertonP3THDP11TABLE_SHAREP14HA_CREATE_INFO
}
{
ConnectSE: unixODBC SQLDriverConnect leaves some "still reachable" pointers
Memcheck:Leak
fun:calloc
...
obj:*/libodbc.so*
fun:SQLDriverConnect
fun:_ZN7ODBConn7ConnectEj
fun:_ZN7ODBConn4OpenEPcj
fun:_Z11ODBCColumnsP7_globalPcS1_S1_b
fun:_ZL26connect_assisted_discoveryP10handlertonP3THDP11TABLE_SHAREP14HA_CREATE_INFO
}
{
ConnectSE: unixODBC SQLDriverConnect leaves some "still reachable" pointers
Memcheck:Leak
fun:malloc
...
obj:*/libodbc.so*
fun:SQLDriverConnect
fun:_ZN7ODBConn7ConnectEj
fun:_ZN7ODBConn4OpenEPcj
fun:_Z11ODBCColumnsP7_globalPcS1_S1_b
fun:_ZL26connect_assisted_discoveryP10handlertonP3THDP11TABLE_SHAREP14HA_CREATE_INFO
}
{
ConnectSE: unixODBC dlopen leaves some "still reachable"
Memcheck:Leak
fun:malloc
fun:expand_dynamic_string_token
...
obj:*/libltdl.so*
...
obj:*/libodbc.so*
}
...@@ -178,7 +178,7 @@ bool COLBLK::InitValue(PGLOBAL g) ...@@ -178,7 +178,7 @@ bool COLBLK::InitValue(PGLOBAL g)
(To_Tdb) ? To_Tdb->GetCat() : NULL))) (To_Tdb) ? To_Tdb->GetCat() : NULL)))
return true; return true;
Status = BUF_READY; AddStatus(BUF_READY);
Value->SetNullable(Nullable); Value->SetNullable(Nullable);
#ifdef DEBTRACE #ifdef DEBTRACE
......
...@@ -592,6 +592,18 @@ PXNODE DOMNODELIST::GetItem(PGLOBAL g, int n, PXNODE np) ...@@ -592,6 +592,18 @@ PXNODE DOMNODELIST::GetItem(PGLOBAL g, int n, PXNODE np)
} // end of GetItem } // end of GetItem
/******************************************************************/
/* Reset the pointer on the deleted item. */
/******************************************************************/
bool DOMNODELIST::DropItem(PGLOBAL g, int n)
{
if (Listp == NULL || Listp->length <= n)
return true;
//Listp->item[n] = NULL; La proprit n'a pas de mthode 'set'
return false;
} // end of DeleteItem
/* ----------------------- class DOMATTR ------------------------ */ /* ----------------------- class DOMATTR ------------------------ */
/******************************************************************/ /******************************************************************/
...@@ -618,8 +630,8 @@ bool DOMATTR::SetText(PGLOBAL g, char *txtp, int len) ...@@ -618,8 +630,8 @@ bool DOMATTR::SetText(PGLOBAL g, char *txtp, int len)
Len = len; Len = len;
} // endif len } // endif len
if (!MultiByteToWideChar(CP_ACP, 0, txtp, strlen(txtp) + 1, if (!MultiByteToWideChar(CP_UTF8, 0, txtp, strlen(txtp) + 1,
Ws, Len + 1)) { Ws, Len + 1)) {
sprintf(g->Message, MSG(WS_CONV_ERR), txtp); sprintf(g->Message, MSG(WS_CONV_ERR), txtp);
return true; return true;
} // endif } // endif
......
...@@ -104,8 +104,9 @@ class DOMNODELIST : public XMLNODELIST { ...@@ -104,8 +104,9 @@ class DOMNODELIST : public XMLNODELIST {
friend class DOMNODE; friend class DOMNODE;
public: public:
// Methods // Methods
virtual int GetLength(void) {return Listp->length;} virtual int GetLength(void) {return Listp->length;}
virtual PXNODE GetItem(PGLOBAL g, int n, PXNODE np); virtual PXNODE GetItem(PGLOBAL g, int n, PXNODE np);
virtual bool DropItem(PGLOBAL g, int n);
protected: protected:
// Constructor // Constructor
......
...@@ -165,7 +165,7 @@ extern "C" char nmfile[]; ...@@ -165,7 +165,7 @@ extern "C" char nmfile[];
extern "C" char pdebug[]; extern "C" char pdebug[];
extern "C" { extern "C" {
char version[]= "Version 1.01.0007 July 26, 2013"; char version[]= "Version 1.01.0008 August 18, 2013";
#if defined(XMSG) #if defined(XMSG)
char msglang[]; // Default message language char msglang[]; // Default message language
...@@ -1093,7 +1093,8 @@ PTDB ha_connect::GetTDB(PGLOBAL g) ...@@ -1093,7 +1093,8 @@ PTDB ha_connect::GetTDB(PGLOBAL g)
if (!xp->CheckQuery(valid_query_id) && tdbp if (!xp->CheckQuery(valid_query_id) && tdbp
&& !stricmp(tdbp->GetName(), table_name) && !stricmp(tdbp->GetName(), table_name)
&& tdbp->GetMode() == xmod) { && (tdbp->GetMode() == xmod
|| tdbp->GetAmType() == TYPE_AM_XML)) {
tp= tdbp; tp= tdbp;
tp->SetMode(xmod); tp->SetMode(xmod);
} else if ((tp= CntGetTDB(g, table_name, xmod, this))) } else if ((tp= CntGetTDB(g, table_name, xmod, this)))
...@@ -1132,13 +1133,14 @@ bool ha_connect::OpenTable(PGLOBAL g, bool del) ...@@ -1132,13 +1133,14 @@ bool ha_connect::OpenTable(PGLOBAL g, bool del)
break; break;
} // endswitch xmode } // endswitch xmode
if (xmod != MODE_INSERT) { if (xmod != MODE_INSERT || tdbp->GetAmType() == TYPE_AM_ODBC
|| tdbp->GetAmType() == TYPE_AM_MYSQL) {
// Get the list of used fields (columns) // Get the list of used fields (columns)
char *p; char *p;
unsigned int k1, k2, n1, n2; unsigned int k1, k2, n1, n2;
Field* *field; Field* *field;
Field* fp; Field* fp;
MY_BITMAP *map= table->read_set; MY_BITMAP *map= (xmod == MODE_INSERT) ? table->write_set : table->read_set;
MY_BITMAP *ump= (xmod == MODE_UPDATE) ? table->write_set : NULL; MY_BITMAP *ump= (xmod == MODE_UPDATE) ? table->write_set : NULL;
k1= k2= 0; k1= k2= 0;
...@@ -1373,7 +1375,8 @@ int ha_connect::ScanRecord(PGLOBAL g, uchar *buf) ...@@ -1373,7 +1375,8 @@ int ha_connect::ScanRecord(PGLOBAL g, uchar *buf)
fp->option_struct->special) fp->option_struct->special)
continue; // Is a virtual column possible here ??? continue; // Is a virtual column possible here ???
if (xmod == MODE_INSERT || if ((xmod == MODE_INSERT && tdbp->GetAmType() != TYPE_AM_MYSQL
&& tdbp->GetAmType() != TYPE_AM_ODBC) ||
bitmap_is_set(table->write_set, fp->field_index)) { bitmap_is_set(table->write_set, fp->field_index)) {
for (colp= tp->GetSetCols(); colp; colp= colp->GetNext()) for (colp= tp->GetSetCols(); colp; colp= colp->GetNext())
if (!stricmp(colp->GetName(), fp->field_name)) if (!stricmp(colp->GetName(), fp->field_name))
...@@ -2658,8 +2661,9 @@ int ha_connect::delete_all_rows() ...@@ -2658,8 +2661,9 @@ int ha_connect::delete_all_rows()
PGLOBAL g= xp->g; PGLOBAL g= xp->g;
DBUG_ENTER("ha_connect::delete_all_rows"); DBUG_ENTER("ha_connect::delete_all_rows");
// Close and reopen the table so it will be deleted if (tdbp && tdbp->GetAmType() != TYPE_AM_XML)
rc= CloseTable(g); // Close and reopen the table so it will be deleted
rc= CloseTable(g);
if (!(OpenTable(g))) { if (!(OpenTable(g))) {
if (CntDeleteRow(g, tdbp, true)) { if (CntDeleteRow(g, tdbp, true)) {
...@@ -3462,7 +3466,7 @@ static bool add_field(String *sql, const char *field_name, int typ, int len, ...@@ -3462,7 +3466,7 @@ static bool add_field(String *sql, const char *field_name, int typ, int len,
{ {
bool error= false; bool error= false;
const char *type= PLGtoMYSQLtype(typ, dbf); const char *type= PLGtoMYSQLtype(typ, dbf);
type= PLGtoMYSQLtype(typ, true); // type= PLGtoMYSQLtype(typ, true); ?????
error|= sql->append('`'); error|= sql->append('`');
error|= sql->append(field_name); error|= sql->append(field_name);
...@@ -3612,6 +3616,7 @@ static int init_table_share(THD *thd, ...@@ -3612,6 +3616,7 @@ static int init_table_share(THD *thd,
static int init_table_share(THD* thd, static int init_table_share(THD* thd,
TABLE_SHARE *table_s, TABLE_SHARE *table_s,
HA_CREATE_INFO *create_info, HA_CREATE_INFO *create_info,
// char *dsn,
String *sql) String *sql)
{ {
bool oom= false; bool oom= false;
...@@ -3670,10 +3675,12 @@ static int init_table_share(THD* thd, ...@@ -3670,10 +3675,12 @@ static int init_table_share(THD* thd,
} // endfor opt } // endfor opt
if (create_info->connect_string.length) { if (create_info->connect_string.length) {
//if (dsn) {
oom|= sql->append(' '); oom|= sql->append(' ');
oom|= sql->append("CONNECTION='"); oom|= sql->append("CONNECTION='");
oom|= sql->append_for_single_quote(create_info->connect_string.str, oom|= sql->append_for_single_quote(create_info->connect_string.str,
create_info->connect_string.length); create_info->connect_string.length);
// oom|= sql->append_for_single_quote(dsn, strlen(dsn));
oom|= sql->append('\''); oom|= sql->append('\'');
if (oom) if (oom)
...@@ -3715,6 +3722,25 @@ static void add_option(THD* thd, HA_CREATE_INFO *create_info, ...@@ -3715,6 +3722,25 @@ static void add_option(THD* thd, HA_CREATE_INFO *create_info,
#endif // NEW_WAY #endif // NEW_WAY
} // end of add_option } // 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 @brief
connect_assisted_discovery() is called when creating a table with no columns. connect_assisted_discovery() is called when creating a table with no columns.
...@@ -3733,13 +3759,13 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, ...@@ -3733,13 +3759,13 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
{ {
char spc= ',', qch= 0; char spc= ',', qch= 0;
const char *fncn= "?"; const char *fncn= "?";
const char *user, *fn, *db, *host, *pwd, *prt, *sep, *tbl, *src; const char *user, *fn, *db, *host, *pwd, *sep, *tbl, *src;
const char *col, *ocl, *rnk, *pic, *fcl; const char *col, *ocl, *rnk, *pic, *fcl;
char *tab, *dsn; char *tab, *dsn;
#if defined(WIN32) #if defined(WIN32)
char *nsp= NULL, *cls= NULL; char *nsp= NULL, *cls= NULL;
#endif // WIN32 #endif // WIN32
int port= 0, hdr= 0, mxr= 0, rc= 0; int port= 0, hdr= 0, mxr= 0, rc= 0, cop= 0;
uint tm, fnc= FNC_NO, supfnc= (FNC_NO | FNC_COL); uint tm, fnc= FNC_NO, supfnc= (FNC_NO | FNC_COL);
bool bif, ok= false, dbf= false; bool bif, ok= false, dbf= false;
TABTYPE ttp= TAB_UNDEF; TABTYPE ttp= TAB_UNDEF;
...@@ -3760,7 +3786,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, ...@@ -3760,7 +3786,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
if (!g) if (!g)
return HA_ERR_INTERNAL_ERROR; return HA_ERR_INTERNAL_ERROR;
user= host= pwd= prt= tbl= src= col= ocl= pic= fcl= rnk= dsn= NULL; user= host= pwd= tbl= src= col= ocl= pic= fcl= rnk= dsn= NULL;
// Get the useful create options // Get the useful create options
ttp= GetTypeID(topt->type); ttp= GetTypeID(topt->type);
...@@ -3778,23 +3804,23 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, ...@@ -3778,23 +3804,23 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
col= topt->colist; col= topt->colist;
if (topt->oplist) { if (topt->oplist) {
host= GetListOption(g,"host", topt->oplist, "localhost"); host= GetListOption(g, "host", topt->oplist, "localhost");
user= GetListOption(g,"user", topt->oplist, "root"); user= GetListOption(g, "user", topt->oplist, "root");
// Default value db can come from the DBNAME=xxx option. // Default value db can come from the DBNAME=xxx option.
db= GetListOption(g,"database", topt->oplist, db); db= GetListOption(g, "database", topt->oplist, db);
col= GetListOption(g,"colist", topt->oplist, col); col= GetListOption(g, "colist", topt->oplist, col);
ocl= GetListOption(g,"occurcol", topt->oplist, NULL); ocl= GetListOption(g, "occurcol", topt->oplist, NULL);
pic= GetListOption(g,"pivotcol", topt->oplist, NULL); pic= GetListOption(g, "pivotcol", topt->oplist, NULL);
fcl= GetListOption(g,"fnccol", topt->oplist, NULL); fcl= GetListOption(g, "fnccol", topt->oplist, NULL);
rnk= GetListOption(g,"rankcol", topt->oplist, NULL); rnk= GetListOption(g, "rankcol", topt->oplist, NULL);
pwd= GetListOption(g,"password", topt->oplist); pwd= GetListOption(g, "password", topt->oplist);
prt= GetListOption(g,"port", topt->oplist);
port= (prt) ? atoi(prt) : 0;
#if defined(WIN32) #if defined(WIN32)
nsp= GetListOption(g,"namespace", topt->oplist); nsp= GetListOption(g, "namespace", topt->oplist);
cls= GetListOption(g,"class", topt->oplist); cls= GetListOption(g, "class", topt->oplist);
#endif // WIN32 #endif // WIN32
port= atoi(GetListOption(g, "port", topt->oplist, "0"));
mxr= atoi(GetListOption(g,"maxerr", topt->oplist, "0")); mxr= atoi(GetListOption(g,"maxerr", topt->oplist, "0"));
cop= atoi(GetListOption(g, "checkdsn", topt->oplist, "0"));
} else { } else {
host= "localhost"; host= "localhost";
user= "root"; user= "root";
...@@ -3840,7 +3866,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, ...@@ -3840,7 +3866,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
} // endif p } // endif p
} else if (ttp != TAB_ODBC || !(fnc & (FNC_TABLE | FNC_COL))) } else if (ttp != TAB_ODBC || !(fnc & (FNC_TABLE | FNC_COL)))
tab= (char*)create_info->alias; tab= table_s->table_name.str; // Default value
#if defined(NEW_WAY) #if defined(NEW_WAY)
add_option(thd, create_info, "tabname", tab); add_option(thd, create_info, "tabname", tab);
...@@ -3850,8 +3876,18 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, ...@@ -3850,8 +3876,18 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
switch (ttp) { switch (ttp) {
#if defined(ODBC_SUPPORT) #if defined(ODBC_SUPPORT)
case TAB_ODBC: case TAB_ODBC:
if (!(dsn= create_info->connect_string.str) dsn= create_info->connect_string.str;
&& !(fnc & (FNC_DSN | FNC_DRIVER)))
if (fnc & (FNC_DSN | FNC_DRIVER))
ok= true;
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
} else if (!dsn)
sprintf(g->Message, "Missing %s connection string", topt->type); sprintf(g->Message, "Missing %s connection string", topt->type);
else else
ok= true; ok= true;
...@@ -3873,31 +3909,46 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, ...@@ -3873,31 +3909,46 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
case TAB_MYSQL: case TAB_MYSQL:
ok= true; ok= true;
if ((dsn= create_info->connect_string.str)) { if (create_info->connect_string.str) {
int len= create_info->connect_string.length;
PMYDEF mydef= new(g) MYSQLDEF(); PMYDEF mydef= new(g) MYSQLDEF();
PDBUSER dup= PlgGetUser(g); PDBUSER dup= PlgGetUser(g);
PCATLG cat= (dup) ? dup->Catalog : NULL; PCATLG cat= (dup) ? dup->Catalog : NULL;
dsn= (char*)PlugSubAlloc(g, NULL, strlen(dsn) + 1); dsn= (char*)PlugSubAlloc(g, NULL, len + 1);
strncpy(dsn, create_info->connect_string.str, strncpy(dsn, create_info->connect_string.str, len);
create_info->connect_string.length); dsn[len]= 0;
dsn[create_info->connect_string.length]= 0;
mydef->SetName(create_info->alias); mydef->SetName(create_info->alias);
mydef->SetCat(cat); mydef->SetCat(cat);
if (!mydef->ParseURL(g, dsn)) { if (!mydef->ParseURL(g, dsn, false)) {
host= mydef->GetHostname(); if (mydef->GetHostname())
user= mydef->GetUsername(); host= mydef->GetHostname();
pwd= mydef->GetPassword();
db= mydef->GetDatabase(); if (mydef->GetUsername())
tab= mydef->GetTabname(); user= mydef->GetUsername();
port= mydef->GetPortnumber();
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 } else
ok= false; ok= false;
} else if (!user) } else if (!user)
user= "root"; user= "root";
if (CheckSelf(g, table_s, host, db, tab, src, port))
ok= false;
break; break;
#endif // MYSQL_SUPPORT #endif // MYSQL_SUPPORT
#if defined(WIN32) #if defined(WIN32)
...@@ -3946,7 +3997,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, ...@@ -3946,7 +3997,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
else else
return HA_ERR_INTERNAL_ERROR; // Should never happen return HA_ERR_INTERNAL_ERROR; // Should never happen
if (src && ttp != TAB_PIVOT) { if (src && ttp != TAB_PIVOT && ttp != TAB_ODBC) {
qrp= SrcColumns(g, host, db, user, pwd, src, port); qrp= SrcColumns(g, host, db, user, pwd, src, port);
if (qrp && ttp == TAB_OCCUR) if (qrp && ttp == TAB_OCCUR)
...@@ -3964,7 +4015,12 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, ...@@ -3964,7 +4015,12 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
switch (fnc) { switch (fnc) {
case FNC_NO: case FNC_NO:
case FNC_COL: case FNC_COL:
qrp= ODBCColumns(g, dsn, (char *) tab, NULL, fnc == FNC_COL); if (src) {
qrp= ODBCSrcCols(g, dsn, (char*)src);
src= NULL; // for next tests
} else
qrp= ODBCColumns(g, dsn, (char *) tab, NULL, fnc == FNC_COL);
break; break;
case FNC_TABLE: case FNC_TABLE:
qrp= ODBCTables(g, dsn, (char *) tab, true); qrp= ODBCTables(g, dsn, (char *) tab, true);
...@@ -4130,6 +4186,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, ...@@ -4130,6 +4186,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
#else // !NEW_WAY #else // !NEW_WAY
if (!rc) if (!rc)
rc= init_table_share(thd, table_s, create_info, &sql); rc= init_table_share(thd, table_s, create_info, &sql);
// rc= init_table_share(thd, table_s, create_info, dsn, &sql);
#endif // !NEW_WAY #endif // !NEW_WAY
return rc; return rc;
...@@ -4250,6 +4307,54 @@ int ha_connect::create(const char *name, TABLE *table_arg, ...@@ -4250,6 +4307,54 @@ int ha_connect::create(const char *name, TABLE *table_arg,
DBUG_RETURN(HA_ERR_INTERNAL_ERROR); DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
} // endif tabname } // 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 */; default: /* do nothing */;
break; break;
} // endswitch ttp } // endswitch ttp
......
...@@ -208,7 +208,8 @@ class ha_connect: public handler ...@@ -208,7 +208,8 @@ class ha_connect: public handler
return (HA_NO_TRANSACTIONS | HA_REC_NOT_IN_SEQ | HA_HAS_RECORDS | return (HA_NO_TRANSACTIONS | HA_REC_NOT_IN_SEQ | HA_HAS_RECORDS |
HA_NO_AUTO_INCREMENT | HA_NO_PREFIX_CHAR_KEYS | HA_NO_AUTO_INCREMENT | HA_NO_PREFIX_CHAR_KEYS |
HA_NO_COPY_ON_ALTER | HA_CAN_VIRTUAL_COLUMNS | HA_NO_COPY_ON_ALTER | HA_CAN_VIRTUAL_COLUMNS |
/*HA_NULL_IN_KEY |*/ HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE); HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE |
/*HA_NULL_IN_KEY |*/ HA_MUST_USE_TABLE_CONDITION_PUSHDOWN);
} }
/** @brief /** @brief
......
...@@ -14,6 +14,10 @@ ...@@ -14,6 +14,10 @@
#include "my_global.h" #include "my_global.h"
//#endif // !WIN32 //#endif // !WIN32
#if !defined(LIBXML_TREE_ENABLED) || !defined(LIBXML_OUTPUT_ENABLED)
#error "tree support not compiled in"
#endif
#if !defined(LIBXML_XPATH_ENABLED) || !defined(LIBXML_SAX1_ENABLED) #if !defined(LIBXML_XPATH_ENABLED) || !defined(LIBXML_SAX1_ENABLED)
#error "XPath not supported" #error "XPath not supported"
#endif #endif
...@@ -47,8 +51,6 @@ typedef struct _x2block { /* Loaded XML file block */ ...@@ -47,8 +51,6 @@ typedef struct _x2block { /* Loaded XML file block */
short Type; /* TYPE_FB_XML */ short Type; /* TYPE_FB_XML */
int Retcode; /* Return code from Load */ int Retcode; /* Return code from Load */
xmlDocPtr Docp; /* Document interface pointer */ xmlDocPtr Docp; /* Document interface pointer */
// xmlXPathContextPtr Ctxp;
// xmlXPathObjectPtr Xop;
} X2BLOCK, *PX2BLOCK; } X2BLOCK, *PX2BLOCK;
/******************************************************************/ /******************************************************************/
...@@ -91,6 +93,8 @@ class LIBXMLDOC : public XMLDOCUMENT { ...@@ -91,6 +93,8 @@ class LIBXMLDOC : public XMLDOCUMENT {
xmlNodeSetPtr Nlist; xmlNodeSetPtr Nlist;
xmlXPathContextPtr Ctxp; xmlXPathContextPtr Ctxp;
xmlXPathObjectPtr Xop; xmlXPathObjectPtr Xop;
xmlXPathObjectPtr NlXop;
xmlErrorPtr Xerr;
char *Buf; // Temporary char *Buf; // Temporary
bool Nofreelist; bool Nofreelist;
}; // end of class LIBXMLDOC }; // end of class LIBXMLDOC
...@@ -141,6 +145,7 @@ class XML2NODELIST : public XMLNODELIST { ...@@ -141,6 +145,7 @@ class XML2NODELIST : public XMLNODELIST {
// Methods // Methods
virtual int GetLength(void); virtual int GetLength(void);
virtual PXNODE GetItem(PGLOBAL g, int n, PXNODE np); virtual PXNODE GetItem(PGLOBAL g, int n, PXNODE np);
virtual bool DropItem(PGLOBAL g, int n);
protected: protected:
// Constructor // Constructor
...@@ -180,6 +185,23 @@ extern int trace; ...@@ -180,6 +185,23 @@ extern int trace;
} // "C" } // "C"
#if defined(MEMORY_TRACE) #if defined(MEMORY_TRACE)
static int m = 0;
static char s[500];
/**************************************************************************/
/* Tracing output function. */
/**************************************************************************/
void xtrc(char const *fmt, ...)
{
va_list ap;
va_start (ap, fmt);
//vfprintf(stderr, fmt, ap);
vsprintf(s, fmt, ap);
if (s[strlen(s)-1] == '\n')
s[strlen(s)-1] = 0;
va_end (ap);
} // end of htrc
static xmlFreeFunc Free; static xmlFreeFunc Free;
static xmlMallocFunc Malloc; static xmlMallocFunc Malloc;
static xmlMallocFunc MallocA; static xmlMallocFunc MallocA;
...@@ -188,42 +210,53 @@ static xmlStrdupFunc Strdup; ...@@ -188,42 +210,53 @@ static xmlStrdupFunc Strdup;
void xmlMyFree(void *mem) void xmlMyFree(void *mem)
{ {
if (trace) if (trace) {
htrc("Freeing at %p\n", mem); htrc("%.4d Freeing at %p %s\n", ++m, mem, s);
*s = 0;
} // endif trace
Free(mem); Free(mem);
} // end of xmlMyFree } // end of xmlMyFree
void *xmlMyMalloc(size_t size) void *xmlMyMalloc(size_t size)
{ {
void *p = Malloc(size); void *p = Malloc(size);
if (trace) if (trace) {
htrc("Allocating %.5d at %p\n", size, p); htrc("%.4d Allocating %.5d at %p %s\n", ++m, size, p, s);
*s = 0;
} // endif trace
return p; return p;
} // end of xmlMyMalloc } // end of xmlMyMalloc
void *xmlMyMallocAtomic(size_t size) void *xmlMyMallocAtomic(size_t size)
{ {
void *p = MallocA(size); void *p = MallocA(size);
if (trace) if (trace) {
htrc("Atom alloc %.5d at %p\n", size, p); htrc("%.4d Atom alloc %.5d at %p %s\n", ++m, size, p, s);
*s = 0;
} // endif trace
return p; return p;
} // end of xmlMyMallocAtomic } // end of xmlMyMallocAtomic
void *xmlMyRealloc(void *mem, size_t size) void *xmlMyRealloc(void *mem, size_t size)
{ {
void *p = Realloc(mem, size); void *p = Realloc(mem, size);
if (trace) if (trace) {
htrc("ReAlloc %.5d to %p from %p\n", size, p, mem); htrc("%.4d ReAlloc %.5d to %p from %p %s\n", ++m, size, p, mem, s);
*s = 0;
} // endif trace
return p; return p;
} // end of xmlMyRealloc } // end of xmlMyRealloc
char *xmlMyStrdup(const char *str) char *xmlMyStrdup(const char *str)
{ {
char *p = Strdup(str); char *p = Strdup(str);
if (trace) if (trace) {
htrc("Duplicating to %p from %p %s\n", p, str, str); htrc("%.4d Duplicating to %p from %p %s %s\n", ++m, p, str, str, s);
*s = 0;
} // endif trace
return p; return p;
} // end of xmlMyStrdup } // end of xmlMyStrdup
#define htrc xtrc
#endif // MEMORY_TRACE #endif // MEMORY_TRACE
/******************************************************************/ /******************************************************************/
...@@ -295,6 +328,8 @@ LIBXMLDOC::LIBXMLDOC(char *nsl, char *nsdf, char *enc, PFBLOCK fp) ...@@ -295,6 +328,8 @@ LIBXMLDOC::LIBXMLDOC(char *nsl, char *nsdf, char *enc, PFBLOCK fp)
Nlist = NULL; Nlist = NULL;
Ctxp = NULL; Ctxp = NULL;
Xop = NULL; Xop = NULL;
NlXop = NULL;
Xerr = NULL;
Buf = NULL; Buf = NULL;
Nofreelist = false; Nofreelist = false;
} // end of LIBXMLDOC constructor } // end of LIBXMLDOC constructor
...@@ -321,9 +356,10 @@ bool LIBXMLDOC::ParseFile(char *fn) ...@@ -321,9 +356,10 @@ bool LIBXMLDOC::ParseFile(char *fn)
Encoding = (char*)Docp->encoding; Encoding = (char*)Docp->encoding;
return false; return false;
} else } else if ((Xerr = xmlGetLastError()))
return true; xmlResetError(Xerr);
return true;
} // end of ParseFile } // end of ParseFile
/******************************************************************/ /******************************************************************/
...@@ -344,8 +380,6 @@ PFBLOCK LIBXMLDOC::LinkXblock(PGLOBAL g, MODE m, int rc, char *fn) ...@@ -344,8 +380,6 @@ PFBLOCK LIBXMLDOC::LinkXblock(PGLOBAL g, MODE m, int rc, char *fn)
xp->Length = (m == MODE_READ) ? 1 : 0; xp->Length = (m == MODE_READ) ? 1 : 0;
xp->Retcode = rc; xp->Retcode = rc;
xp->Docp = Docp; xp->Docp = Docp;
// xp->Ctxp = Ctxp;
// xp->Xop = Xop;
// Return xp as a fp // Return xp as a fp
return (PFBLOCK)xp; return (PFBLOCK)xp;
...@@ -356,6 +390,9 @@ PFBLOCK LIBXMLDOC::LinkXblock(PGLOBAL g, MODE m, int rc, char *fn) ...@@ -356,6 +390,9 @@ PFBLOCK LIBXMLDOC::LinkXblock(PGLOBAL g, MODE m, int rc, char *fn)
/******************************************************************/ /******************************************************************/
bool LIBXMLDOC::NewDoc(PGLOBAL g, char *ver) bool LIBXMLDOC::NewDoc(PGLOBAL g, char *ver)
{ {
if (trace)
htrc("NewDoc\n");
return ((Docp = xmlNewDoc(BAD_CAST ver)) == NULL); return ((Docp = xmlNewDoc(BAD_CAST ver)) == NULL);
} // end of NewDoc } // end of NewDoc
...@@ -462,8 +499,7 @@ int LIBXMLDOC::DumpDoc(PGLOBAL g, char *ofn) ...@@ -462,8 +499,7 @@ int LIBXMLDOC::DumpDoc(PGLOBAL g, char *ofn)
if (xmlSaveFormatFileEnc((const char *)ofn, Docp, Encoding, 0) < 0) { if (xmlSaveFormatFileEnc((const char *)ofn, Docp, Encoding, 0) < 0) {
xmlErrorPtr err = xmlGetLastError(); xmlErrorPtr err = xmlGetLastError();
strcpy(g->Message, (err) ? err->message : "Error saving XML doc" strcpy(g->Message, (err) ? err->message : "Error saving XML doc");
);
rc = -1; rc = -1;
} // endif Save } // endif Save
// rc = xmlDocDump(of, Docp); // rc = xmlDocDump(of, Docp);
...@@ -497,17 +533,44 @@ void LIBXMLDOC::CloseDoc(PGLOBAL g, PFBLOCK xp) ...@@ -497,17 +533,44 @@ void LIBXMLDOC::CloseDoc(PGLOBAL g, PFBLOCK xp)
if (trace) if (trace)
htrc("CloseDoc: xp=%p count=%d\n", xp, (xp) ? xp->Count : 0); htrc("CloseDoc: xp=%p count=%d\n", xp, (xp) ? xp->Count : 0);
if (xp && xp->Count == 1) { //if (xp && xp->Count == 1) {
if (Nlist) if (Nlist) {
xmlXPathFreeNodeSet(Nlist); xmlXPathFreeNodeSet(Nlist);
if (Xop) if ((Xerr = xmlGetLastError()))
xmlResetError(Xerr);
Nlist = NULL;
} // endif Nlist
if (Xop) {
xmlXPathFreeObject(Xop); xmlXPathFreeObject(Xop);
if (Ctxp) if ((Xerr = xmlGetLastError()))
xmlResetError(Xerr);
Xop = NULL;
} // endif Xop
if (NlXop) {
xmlXPathFreeObject(NlXop);
if ((Xerr = xmlGetLastError()))
xmlResetError(Xerr);
NlXop = NULL;
} // endif NlXop
if (Ctxp) {
xmlXPathFreeContext(Ctxp); xmlXPathFreeContext(Ctxp);
} // endif Count if ((Xerr = xmlGetLastError()))
xmlResetError(Xerr);
Ctxp = NULL;
} // endif Ctxp
// } // endif Count
CloseXML2File(g, xp, false); CloseXML2File(g, xp, false);
} // end of Close } // end of Close
...@@ -560,18 +623,29 @@ xmlNodeSetPtr LIBXMLDOC::GetNodeList(PGLOBAL g, xmlNodePtr np, char *xp) ...@@ -560,18 +623,29 @@ xmlNodeSetPtr LIBXMLDOC::GetNodeList(PGLOBAL g, xmlNodePtr np, char *xp)
} // endfor nsp } // endfor nsp
} else { } // endif Ctxp
if (Xop) {
if (trace) if (trace)
htrc("Calling xmlXPathFreeNodeSetList Xop=%p\n", Xop); htrc("Calling xmlXPathFreeNodeSetList Xop=%p NOFREE=%d\n",
Xop, Nofreelist);
if (Nofreelist) { if (Nofreelist) {
// Making Nlist that must not be freed yet // Making Nlist that must not be freed yet
xmlXPathFreeNodeSetList(Xop); // Caused memory leak // xmlXPathFreeNodeSetList(Xop); // Caused memory leak
assert(!NlXop);
NlXop = Xop; // Freed on closing
Nofreelist = false; Nofreelist = false;
} else } else
xmlXPathFreeObject(Xop); // Caused node not found xmlXPathFreeObject(Xop); // Caused node not found
} // endif Ctxp if ((Xerr = xmlGetLastError())) {
strcpy(g->Message, Xerr->message);
xmlResetError(Xerr);
return NULL;
} // endif Xerr
} // endif Xop
// Set the context to the calling node // Set the context to the calling node
Ctxp->node = np; Ctxp->node = np;
...@@ -990,6 +1064,8 @@ void XML2NODE::AddText(PGLOBAL g, char *txtp) ...@@ -990,6 +1064,8 @@ void XML2NODE::AddText(PGLOBAL g, char *txtp)
/******************************************************************/ /******************************************************************/
void XML2NODE::DeleteChild(PGLOBAL g, PXNODE dnp) void XML2NODE::DeleteChild(PGLOBAL g, PXNODE dnp)
{ {
xmlErrorPtr xerr;
if (trace) if (trace)
htrc("DeleteChild: node=%p\n", dnp); htrc("DeleteChild: node=%p\n", dnp);
...@@ -999,12 +1075,39 @@ void XML2NODE::DeleteChild(PGLOBAL g, PXNODE dnp) ...@@ -999,12 +1075,39 @@ void XML2NODE::DeleteChild(PGLOBAL g, PXNODE dnp)
// This is specific to row nodes // This is specific to row nodes
if (text && text->type == XML_TEXT_NODE) { if (text && text->type == XML_TEXT_NODE) {
xmlUnlinkNode(text); xmlUnlinkNode(text);
if ((xerr = xmlGetLastError()))
goto err;
xmlFreeNode(text); xmlFreeNode(text);
if ((xerr = xmlGetLastError()))
goto err;
} // endif type } // endif type
xmlUnlinkNode(np); xmlUnlinkNode(np);
if ((xerr = xmlGetLastError()))
goto err;
xmlFreeNode(np); xmlFreeNode(np);
if ((xerr = xmlGetLastError()))
goto err;
Delete(dnp); Delete(dnp);
if ((xerr = xmlGetLastError()))
goto err;
return;
err:
if (trace)
htrc("DeleteChild: errmsg=%s\n", xerr->message);
xmlResetError(xerr);
} // end of DeleteChild } // end of DeleteChild
/* -------------------- class XML2NODELIST ---------------------- */ /* -------------------- class XML2NODELIST ---------------------- */
...@@ -1045,6 +1148,22 @@ PXNODE XML2NODELIST::GetItem(PGLOBAL g, int n, PXNODE np) ...@@ -1045,6 +1148,22 @@ PXNODE XML2NODELIST::GetItem(PGLOBAL g, int n, PXNODE np)
} // end of GetItem } // end of GetItem
/******************************************************************/
/* Reset the pointer on the deleted item. */
/******************************************************************/
bool XML2NODELIST::DropItem(PGLOBAL g, int n)
{
if (trace)
htrc("DropItem: n=%d\n", n);
// We should do something here
if (!Listp || Listp->nodeNr <= n)
return true;
Listp->nodeTab[n] = NULL; // This was causing Valgrind warning
return false;
} // end of DropItem
/* ---------------------- class XML2ATTR ------------------------ */ /* ---------------------- class XML2ATTR ------------------------ */
/******************************************************************/ /******************************************************************/
......
...@@ -89,7 +89,7 @@ PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db, ...@@ -89,7 +89,7 @@ PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db,
static unsigned int length[] = {0, 4, 16, 4, 4, 4, 4, 4, 256, 32, 32}; static unsigned int length[] = {0, 4, 16, 4, 4, 4, 4, 4, 256, 32, 32};
char *fld, *fmt, cmd[128]; char *fld, *fmt, cmd[128];
int i, n, nf, ncol = sizeof(buftyp) / sizeof(int); int i, n, nf, ncol = sizeof(buftyp) / sizeof(int);
int len, type, prec, rc, k = 0; int len, type, prec, rc, k = 0;
PQRYRES qrp; PQRYRES qrp;
PCOLRES crp; PCOLRES crp;
MYSQLC myc; MYSQLC myc;
...@@ -166,7 +166,7 @@ PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db, ...@@ -166,7 +166,7 @@ PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db,
// Get type, type name, and precision // Get type, type name, and precision
fld = myc.GetCharField(1); fld = myc.GetCharField(1);
prec = 0; prec = 0;
len = 256; // Default for text or blob len = 255; // Default for text or blob
if ((nf = sscanf(fld, "%[^(](%d,%d", cmd, &len, &prec)) < 1) { if ((nf = sscanf(fld, "%[^(](%d,%d", cmd, &len, &prec)) < 1) {
sprintf(g->Message, MSG(BAD_FIELD_TYPE), fld); sprintf(g->Message, MSG(BAD_FIELD_TYPE), fld);
......
...@@ -54,6 +54,7 @@ uint GetDefaultPort(void); ...@@ -54,6 +54,7 @@ uint GetDefaultPort(void);
class DllItem MYSQLC { class DllItem MYSQLC {
friend class TDBMYSQL; friend class TDBMYSQL;
friend class MYSQLCOL; friend class MYSQLCOL;
friend class TDBMYEXC;
// Construction // Construction
public: public:
MYSQLC(void); MYSQLC(void);
......
...@@ -217,3 +217,24 @@ t2 CREATE TABLE `t2` ( ...@@ -217,3 +217,24 @@ t2 CREATE TABLE `t2` (
SELECT * FROM t2; SELECT * FROM t2;
a a
DROP TABLE t2, t1; DROP TABLE t2, t1;
#
# MDEV-4877 mysqldump dumps all data from a connect table
#
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (10),(20),(30);
CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL CONNECTION='mysql://root@localhost:PORT/test/t1';
SELECT * FROM t2;
a
10
20
30
# Start of mysqldump ------
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `t2` (
`a` int(11) DEFAULT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mysql://root@localhost:PORT/test/t1' `TABLE_TYPE`='MYSQL';
/*!40101 SET character_set_client = @saved_cs_client */;
# End of mysqldump ------
DROP TABLE t2;
DROP TABLE t1;
...@@ -413,7 +413,7 @@ DROP TABLE t1; ...@@ -413,7 +413,7 @@ DROP TABLE t1;
SET @a=LOAD_FILE('MYSQLD_DATADIR/test/t1.xml'); SET @a=LOAD_FILE('MYSQLD_DATADIR/test/t1.xml');
SELECT CAST(@a AS CHAR CHARACTER SET latin1); SELECT CAST(@a AS CHAR CHARACTER SET latin1);
CAST(@a AS CHAR CHARACTER SET latin1) <?xml version="1.0" encoding="iso-8859-1"?> CAST(@a AS CHAR CHARACTER SET latin1) <?xml version="1.0" encoding="iso-8859-1"?>
<!-- Created by CONNECT Version 1.01.0007 July 26, 2013 --> <!-- Created by CONNECT Version 1.01.0008 August 18, 2013 -->
<t1> <t1>
<line> <line>
<node>ÀÁÂÃ</node> <node>ÀÁÂÃ</node>
......
...@@ -10,7 +10,7 @@ let $PORT= `select @@port`; ...@@ -10,7 +10,7 @@ let $PORT= `select @@port`;
--disable_query_log --disable_query_log
--replace_result $PORT PORT --replace_result $PORT PORT
--error 0,ER_UNKNOWN_ERROR --error 0,ER_UNKNOWN_ERROR
--eval CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' --eval CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='tx1' OPTION_LIST='host=localhost,user=root,port=$PORT'
if (!`SELECT count(*) FROM INFORMATION_SCHEMA.TABLES if (!`SELECT count(*) FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1' WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1'
AND ENGINE='CONNECT' AND ENGINE='CONNECT'
...@@ -420,3 +420,17 @@ DROP TABLE t2, t1; ...@@ -420,3 +420,17 @@ DROP TABLE t2, t1;
# TODO: add test for YEAR # TODO: add test for YEAR
# TODO: add tests for fractional seconds # TODO: add tests for fractional seconds
--echo #
--echo # MDEV-4877 mysqldump dumps all data from a connect table
--echo #
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (10),(20),(30);
--replace_result $PORT PORT
--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL CONNECTION='mysql://root@localhost:$PORT/test/t1'
SELECT * FROM t2;
--echo # Start of mysqldump ------
--replace_result $PORT PORT
--exec $MYSQL_DUMP --compact test t2
--echo # End of mysqldump ------
DROP TABLE t2;
DROP TABLE t1;
-- source include/not_embedded.inc -- source include/not_embedded.inc
let $PORT= `select @@port`; let $PORT= `select @@port`;
--disable_query_log --disable_query_log
--replace_result $PORT PORT --replace_result $PORT PORT
--error 0,ER_UNKNOWN_ERROR --error 0,ER_UNKNOWN_ERROR
--eval CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' --eval CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='tx1' OPTION_LIST='host=localhost,user=root,port=$PORT'
if (!`SELECT count(*) FROM INFORMATION_SCHEMA.TABLES if (!`SELECT count(*) FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1' WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1'
AND ENGINE='CONNECT' AND ENGINE='CONNECT'
AND CREATE_OPTIONS LIKE '%`table_type`=MySQL%'`) AND CREATE_OPTIONS LIKE '%`table_type`=MySQL%'`)
{ {
Skip Need MySQL support; Skip Need MySQL support;
} }
DROP TABLE t1; DROP TABLE t1;
--enable_query_log --enable_query_log
--echo # --echo #
--echo # Testing FILE privilege --echo # Testing FILE privilege
--echo # --echo #
GRANT ALL PRIVILEGES ON *.* TO user@localhost; GRANT ALL PRIVILEGES ON *.* TO user@localhost;
REVOKE FILE ON *.* FROM user@localhost; REVOKE FILE ON *.* FROM user@localhost;
--connect(user,localhost,user,,) --connect(user,localhost,user,,)
--connection user --connection user
SELECT user(); SELECT user();
--replace_result $PORT PORT --replace_result $PORT PORT
--error ER_ACCESS_DENIED_ERROR --error ER_ACCESS_DENIED_ERROR
--eval CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=MySQL OPTION_LIST='host=localhost,user=root1,port=$PORT' --eval CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=MySQL OPTION_LIST='host=localhost,user=root1,port=$PORT'
--connection default --connection default
SELECT user(); SELECT user();
CREATE TABLE t1remote (a INT NOT NULL); CREATE TABLE t1remote (a INT NOT NULL);
INSERT INTO t1remote VALUES (10),(20),(30); INSERT INTO t1remote VALUES (10),(20),(30);
--replace_result $PORT PORT --replace_result $PORT PORT
--eval CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=MySQL TABNAME=t1remote OPTION_LIST='host=localhost,user=root,port=$PORT' --eval CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=MySQL TABNAME=t1remote OPTION_LIST='host=localhost,user=root,port=$PORT'
SELECT * FROM t1; SELECT * FROM t1;
--connection user --connection user
SELECT user(); SELECT user();
--error ER_ACCESS_DENIED_ERROR --error ER_ACCESS_DENIED_ERROR
SELECT * FROM t1; SELECT * FROM t1;
--error ER_ACCESS_DENIED_ERROR --error ER_ACCESS_DENIED_ERROR
INSERT INTO t1 VALUES ('xxx'); INSERT INTO t1 VALUES ('xxx');
--error ER_ACCESS_DENIED_ERROR --error ER_ACCESS_DENIED_ERROR
DELETE FROM t1 WHERE a='xxx'; DELETE FROM t1 WHERE a='xxx';
--error ER_ACCESS_DENIED_ERROR --error ER_ACCESS_DENIED_ERROR
UPDATE t1 SET a='yyy' WHERE a='xxx'; UPDATE t1 SET a='yyy' WHERE a='xxx';
--error ER_ACCESS_DENIED_ERROR --error ER_ACCESS_DENIED_ERROR
TRUNCATE TABLE t1; TRUNCATE TABLE t1;
--error ER_ACCESS_DENIED_ERROR --error ER_ACCESS_DENIED_ERROR
ALTER TABLE t1 READONLY=1; ALTER TABLE t1 READONLY=1;
--error ER_ACCESS_DENIED_ERROR --error ER_ACCESS_DENIED_ERROR
CREATE VIEW v1 AS SELECT * FROM t1; CREATE VIEW v1 AS SELECT * FROM t1;
--echo # Testing a VIEW created with FILE privileges but accessed with no FILE --echo # Testing a VIEW created with FILE privileges but accessed with no FILE
--connection default --connection default
SELECT user(); SELECT user();
CREATE VIEW v1 AS SELECT * FROM t1; CREATE VIEW v1 AS SELECT * FROM t1;
--connection user --connection user
SELECT user(); SELECT user();
--error ER_ACCESS_DENIED_ERROR --error ER_ACCESS_DENIED_ERROR
SELECT * FROM v1; SELECT * FROM v1;
--error ER_ACCESS_DENIED_ERROR --error ER_ACCESS_DENIED_ERROR
INSERT INTO v1 VALUES (2); INSERT INTO v1 VALUES (2);
--error ER_ACCESS_DENIED_ERROR --error ER_ACCESS_DENIED_ERROR
UPDATE v1 SET a=123; UPDATE v1 SET a=123;
--error ER_ACCESS_DENIED_ERROR --error ER_ACCESS_DENIED_ERROR
DELETE FROM v1; DELETE FROM v1;
--disconnect user --disconnect user
--connection default --connection default
SELECT user(); SELECT user();
DROP VIEW v1; DROP VIEW v1;
DROP TABLE t1, t1remote; DROP TABLE t1, t1remote;
DROP USER user@localhost; DROP USER user@localhost;
--echo # --echo #
--echo # Testing FILE privileges done --echo # Testing FILE privileges done
--echo # --echo #
/***********************************************************************/ /***********************************************************************/
/* ODBC catalog function prototypes. */ /* ODBC catalog function prototypes. */
/***********************************************************************/ /***********************************************************************/
char *ODBCCheckConnection(PGLOBAL g, char *dsn, int cop);
PQRYRES ODBCDataSources(PGLOBAL g, bool info); PQRYRES ODBCDataSources(PGLOBAL g, bool info);
PQRYRES ODBCColumns(PGLOBAL g, char *dsn, char *table, PQRYRES ODBCColumns(PGLOBAL g, char *dsn, char *table,
char *colpat, bool info); char *colpat, bool info);
PQRYRES ODBCSrcCols(PGLOBAL g, char *dsn, char *src);
PQRYRES ODBCTables(PGLOBAL g, char *dsn, char *tabpat, bool info); PQRYRES ODBCTables(PGLOBAL g, char *dsn, char *tabpat, bool info);
PQRYRES ODBCDrivers(PGLOBAL g, bool info); PQRYRES ODBCDrivers(PGLOBAL g, bool info);
/************ Odbconn C++ Functions Source Code File (.CPP) ************/ /************ Odbconn C++ Functions Source Code File (.CPP) ************/
/* Name: ODBCONN.CPP Version 1.6 */ /* Name: ODBCONN.CPP Version 1.7 */
/* */ /* */
/* (C) Copyright to the author Olivier BERTRAND 1998-2013 */ /* (C) Copyright to the author Olivier BERTRAND 1998-2013 */
/* */ /* */
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#if defined(WIN32) #if defined(WIN32)
//nclude <io.h> //nclude <io.h>
//nclude <fcntl.h> //nclude <fcntl.h>
#include <direct.h> // for getcwd
#if defined(__BORLANDC__) #if defined(__BORLANDC__)
#define __MFC_COMPAT__ // To define min/max as macro #define __MFC_COMPAT__ // To define min/max as macro
#endif #endif
...@@ -76,8 +77,9 @@ static short GetSQLType(int type) ...@@ -76,8 +77,9 @@ static short GetSQLType(int type)
case TYPE_SHORT: tp = SQL_SMALLINT; break; case TYPE_SHORT: tp = SQL_SMALLINT; break;
case TYPE_INT: tp = SQL_INTEGER; break; case TYPE_INT: tp = SQL_INTEGER; break;
case TYPE_DATE: tp = SQL_TIMESTAMP; break; case TYPE_DATE: tp = SQL_TIMESTAMP; break;
case TYPE_BIGINT: tp = SQL_BIGINT; break; // (-5) case TYPE_BIGINT: tp = SQL_BIGINT; break; // (-5)
case TYPE_FLOAT: tp = SQL_DOUBLE; break; case TYPE_FLOAT: tp = SQL_DOUBLE; break;
case TYPE_TINY : tp = SQL_TINYINT; break;
} // endswitch type } // endswitch type
return tp; return tp;
...@@ -97,6 +99,7 @@ static int GetSQLCType(int type) ...@@ -97,6 +99,7 @@ static int GetSQLCType(int type)
case TYPE_DATE: tp = SQL_C_TIMESTAMP; break; case TYPE_DATE: tp = SQL_C_TIMESTAMP; break;
case TYPE_BIGINT: tp = SQL_C_SBIGINT; break; case TYPE_BIGINT: tp = SQL_C_SBIGINT; break;
case TYPE_FLOAT: tp = SQL_C_DOUBLE; break; case TYPE_FLOAT: tp = SQL_C_DOUBLE; break;
case TYPE_TINY : tp = SQL_C_TINYINT; break;
} // endswitch type } // endswitch type
return tp; return tp;
...@@ -127,9 +130,11 @@ int TranslateSQLType(int stp, int prec, int& len) ...@@ -127,9 +130,11 @@ int TranslateSQLType(int stp, int prec, int& len)
type = TYPE_INT; type = TYPE_INT;
break; break;
case SQL_SMALLINT: // 5 case SQL_SMALLINT: // 5
type = TYPE_SHORT;
break;
case SQL_TINYINT: // (-6) case SQL_TINYINT: // (-6)
case SQL_BIT: // (-7) case SQL_BIT: // (-7)
type = TYPE_SHORT; type = TYPE_TINY;
break; break;
case SQL_FLOAT: // 6 case SQL_FLOAT: // 6
case SQL_REAL: // 7 case SQL_REAL: // 7
...@@ -168,10 +173,36 @@ int TranslateSQLType(int stp, int prec, int& len) ...@@ -168,10 +173,36 @@ int TranslateSQLType(int stp, int prec, int& len)
} // end of TranslateSQLType } // end of TranslateSQLType
/***********************************************************************/ /***********************************************************************/
/* ODBConn static members initialization. */ /* ODBCCheckConnection: Check completeness of connection string. */
/***********************************************************************/ /***********************************************************************/
//HENV ODBConn::m_henv = SQL_NULL_HENV; char *ODBCCheckConnection(PGLOBAL g, char *dsn, int cop)
//int ODBConn::m_nAlloc = 0; // per-Appl reference to HENV above {
char *newdsn, dir[_MAX_PATH], buf[_MAX_PATH];
int rc;
DWORD options = ODBConn::openReadOnly;
ODBConn *ocp = new(g) ODBConn(g, NULL);
(void) getcwd(dir, sizeof(dir) - 1);
switch (cop) {
case 1: options |= ODBConn::forceOdbcDialog; break;
case 2: options |= ODBConn::noOdbcDialog; break;
} // endswitch cop
if (ocp->Open(dsn, options) < 1)
newdsn = NULL;
else
newdsn = ocp->GetConnect();
(void) getcwd(buf, sizeof(buf) - 1);
// Some data sources change the current directory
if (strcmp(dir, buf))
rc = chdir(dir);
ocp->Close();
return newdsn; // Return complete connection string
} // end of ODBCCheckConnection
/***********************************************************************/ /***********************************************************************/
/* Allocate the structure used to refer to the result set. */ /* Allocate the structure used to refer to the result set. */
...@@ -225,7 +256,6 @@ static void ResetNullValues(CATPARM *cap) ...@@ -225,7 +256,6 @@ static void ResetNullValues(CATPARM *cap)
/***********************************************************************/ /***********************************************************************/
/* ODBCColumns: constructs the result blocks containing all columns */ /* ODBCColumns: constructs the result blocks containing all columns */
/* of an ODBC table that will be retrieved by GetData commands. */ /* of an ODBC table that will be retrieved by GetData commands. */
/* Note: The first two columns (Qualifier, Owner) are ignored. */
/***********************************************************************/ /***********************************************************************/
PQRYRES ODBCColumns(PGLOBAL g, char *dsn, char *table, PQRYRES ODBCColumns(PGLOBAL g, char *dsn, char *table,
char *colpat, bool info) char *colpat, bool info)
...@@ -251,7 +281,7 @@ PQRYRES ODBCColumns(PGLOBAL g, char *dsn, char *table, ...@@ -251,7 +281,7 @@ PQRYRES ODBCColumns(PGLOBAL g, char *dsn, char *table,
if (!info) { if (!info) {
ocp = new(g) ODBConn(g, NULL); ocp = new(g) ODBConn(g, NULL);
if (ocp->Open(dsn, 2) < 1) // 2 is openReadOnly if (ocp->Open(dsn, 10) < 1) // openReadOnly + noODBCdialog
return NULL; return NULL;
// We fix a MySQL limit because some data sources return 32767 // We fix a MySQL limit because some data sources return 32767
...@@ -314,6 +344,17 @@ PQRYRES ODBCColumns(PGLOBAL g, char *dsn, char *table, ...@@ -314,6 +344,17 @@ PQRYRES ODBCColumns(PGLOBAL g, char *dsn, char *table,
return qrp; return qrp;
} // end of ODBCColumns } // end of ODBCColumns
/**************************************************************************/
/* ODBCSrcCols: constructs the result blocks containing the */
/* description of all the columns of a Srcdef option. */
/**************************************************************************/
PQRYRES ODBCSrcCols(PGLOBAL g, char *dsn, char *src)
{
ODBConn *ocp = new(g) ODBConn(g, NULL);
return ocp->GetMetaData(g, dsn, src);
} // end of ODBCSrcCols
#if 0 #if 0
/**************************************************************************/ /**************************************************************************/
/* MyODBCCols: returns column info as required by ha_connect::pre_create. */ /* MyODBCCols: returns column info as required by ha_connect::pre_create. */
...@@ -800,6 +841,17 @@ void DBX::BuildErrorMessage(ODBConn* pdb, HSTMT hstmt) ...@@ -800,6 +841,17 @@ void DBX::BuildErrorMessage(ODBConn* pdb, HSTMT hstmt)
} // end of BuildErrorMessage } // end of BuildErrorMessage
const char *DBX::GetErrorMessage(int i)
{
if (i < 0 || i >= MAX_NUM_OF_MSG)
return "No ODBC error";
else if (m_ErrMsg[i])
return m_ErrMsg[i];
else
return (m_Msg) ? m_Msg : "Unknown error";
} // end of GetErrorMessage
/***********************************************************************/ /***********************************************************************/
/* ODBConn construction/destruction. */ /* ODBConn construction/destruction. */
/***********************************************************************/ /***********************************************************************/
...@@ -818,7 +870,7 @@ ODBConn::ODBConn(PGLOBAL g, TDBODBC *tdbp) ...@@ -818,7 +870,7 @@ ODBConn::ODBConn(PGLOBAL g, TDBODBC *tdbp)
m_Catver = (tdbp) ? tdbp->Catver : 0; m_Catver = (tdbp) ? tdbp->Catver : 0;
m_Connect = NULL; m_Connect = NULL;
m_Updatable = true; m_Updatable = true;
//m_Transactions = false; m_Transact = false;
m_IDQuoteChar = '\''; m_IDQuoteChar = '\'';
//*m_ErrMsg = '\0'; //*m_ErrMsg = '\0';
} // end of ODBConn } // end of ODBConn
...@@ -1061,7 +1113,7 @@ bool ODBConn::Connect(DWORD Options) ...@@ -1061,7 +1113,7 @@ bool ODBConn::Connect(DWORD Options)
if (hWnd == NULL) if (hWnd == NULL)
hWnd = GetDesktopWindow(); hWnd = GetDesktopWindow();
#else // !WIN32 #else // !WIN32
HWND hWnd = NULL; HWND hWnd = 1;
#endif // !WIN32 #endif // !WIN32
PGLOBAL& g = m_G; PGLOBAL& g = m_G;
PDBUSER dup = PlgGetUser(g); PDBUSER dup = PlgGetUser(g);
...@@ -1204,8 +1256,7 @@ int ODBConn::ExecDirectSQL(char *sql, ODBCCOL *tocols) ...@@ -1204,8 +1256,7 @@ int ODBConn::ExecDirectSQL(char *sql, ODBCCOL *tocols)
void *buffer; void *buffer;
bool b; bool b;
UWORD n; UWORD n;
SWORD ncol, len, tp; SWORD len, tp, ncol = 0;
SQLLEN afrw;
ODBCCOL *colp; ODBCCOL *colp;
RETCODE rc; RETCODE rc;
HSTMT hstmt; HSTMT hstmt;
...@@ -1240,26 +1291,44 @@ int ODBConn::ExecDirectSQL(char *sql, ODBCCOL *tocols) ...@@ -1240,26 +1291,44 @@ int ODBConn::ExecDirectSQL(char *sql, ODBCCOL *tocols)
if (trace) if (trace)
htrc("ExecDirect hstmt=%p %.64s\n", hstmt, sql); htrc("ExecDirect hstmt=%p %.64s\n", hstmt, sql);
do { if (m_Tdb->Srcdef) {
rc = SQLExecDirect(hstmt, (PUCHAR)sql, SQL_NTS); // Be sure this is a query returning a result set
} while (rc == SQL_STILL_EXECUTING); do {
rc = SQLPrepare(hstmt, (PUCHAR)sql, SQL_NTS);
} while (rc == SQL_STILL_EXECUTING);
if (!Check(rc)) if (!Check(rc))
ThrowDBX(rc, "SQLExecDirect", hstmt); ThrowDBX(rc, "SQLPrepare", hstmt);
do { if (!Check(rc = SQLNumResultCols(hstmt, &ncol)))
rc = SQLNumResultCols(hstmt, &ncol); ThrowDBX(rc, "SQLNumResultCols", hstmt);
} while (rc == SQL_STILL_EXECUTING);
if (ncol == 0) {
strcpy(g->Message, "This Srcdef does not return a result set");
return -1;
} // endif ncol
// Ok, now we can proceed
do {
rc = SQLExecute(hstmt);
} while (rc == SQL_STILL_EXECUTING);
if (ncol == 0) { if (!Check(rc))
// Update or Delete statement ThrowDBX(rc, "SQLExecute", hstmt);
rc = SQLRowCount(hstmt, &afrw);
} else {
do {
rc = SQLExecDirect(hstmt, (PUCHAR)sql, SQL_NTS);
} while (rc == SQL_STILL_EXECUTING);
if (!Check(rc)) if (!Check(rc))
ThrowDBX(rc, "SQLRowCount", hstmt); ThrowDBX(rc, "SQLExecDirect", hstmt);
return afrw; do {
} // endif ncol rc = SQLNumResultCols(hstmt, &ncol);
} while (rc == SQL_STILL_EXECUTING);
} // endif Srcdef
for (n = 0, colp = tocols; colp; colp = (PODBCCOL)colp->GetNext()) for (n = 0, colp = tocols; colp; colp = (PODBCCOL)colp->GetNext())
if (!colp->IsSpecial()) if (!colp->IsSpecial())
...@@ -1407,10 +1476,33 @@ int ODBConn::PrepareSQL(char *sql) ...@@ -1407,10 +1476,33 @@ int ODBConn::PrepareSQL(char *sql)
{ {
PGLOBAL& g = m_G; PGLOBAL& g = m_G;
bool b; bool b;
UINT txn = 0;
SWORD nparm; SWORD nparm;
RETCODE rc; RETCODE rc;
HSTMT hstmt; HSTMT hstmt;
if (m_Tdb->GetMode() != MODE_READ) {
// Does the data source support transactions
rc = SQLGetInfo(m_hdbc, SQL_TXN_CAPABLE, &txn, 0, NULL);
if (Check(rc) && txn != SQL_TC_NONE) try {
rc = SQLSetConnectAttr(m_hdbc, SQL_ATTR_AUTOCOMMIT,
SQL_AUTOCOMMIT_OFF, SQL_IS_UINTEGER);
if (!Check(rc))
ThrowDBX(SQL_INVALID_HANDLE, "SQLSetConnectAttr");
m_Transact = true;
} catch(DBX *x) {
if (trace)
for (int i = 0; i < MAX_NUM_OF_MSG && x->m_ErrMsg[i]; i++)
htrc(x->m_ErrMsg[i]);
strcpy(g->Message, x->GetErrorMessage(0));
} // end try/catch
} // endif Mode
try { try {
b = false; b = false;
...@@ -1450,13 +1542,19 @@ int ODBConn::PrepareSQL(char *sql) ...@@ -1450,13 +1542,19 @@ int ODBConn::PrepareSQL(char *sql)
for (int i = 0; i < MAX_NUM_OF_MSG && x->m_ErrMsg[i]; i++) for (int i = 0; i < MAX_NUM_OF_MSG && x->m_ErrMsg[i]; i++)
htrc(x->m_ErrMsg[i]); htrc(x->m_ErrMsg[i]);
strcpy(m_G->Message, x->GetErrorMessage(0)); strcpy(g->Message, x->GetErrorMessage(0));
if (b) if (b)
SQLCancel(hstmt); SQLCancel(hstmt);
rc = SQLFreeStmt(hstmt, SQL_DROP); rc = SQLFreeStmt(hstmt, SQL_DROP);
m_hstmt = NULL; m_hstmt = NULL;
if (m_Transact) {
rc = SQLEndTran(SQL_HANDLE_DBC, m_hdbc, SQL_ROLLBACK);
m_Transact = false;
} // endif m_Transact
return -1; return -1;
} // end try/catch } // end try/catch
...@@ -1465,27 +1563,59 @@ int ODBConn::PrepareSQL(char *sql) ...@@ -1465,27 +1563,59 @@ int ODBConn::PrepareSQL(char *sql)
} // end of PrepareSQL } // end of PrepareSQL
/***********************************************************************/ /***********************************************************************/
/* Bind a parameter for inserting. */ /* Execute a prepared statement. */
/***********************************************************************/ /***********************************************************************/
bool ODBConn::ExecuteSQL(void) int ODBConn::ExecuteSQL(bool x)
{ {
RETCODE rc; PGLOBAL& g = m_G;
SWORD ncol = 0;
RETCODE rc;
SQLLEN afrw = -1;
try { try {
rc = SQLExecute(m_hstmt); do {
rc = SQLExecute(m_hstmt);
} while (rc == SQL_STILL_EXECUTING);
if (!Check(rc)) if (!Check(rc))
ThrowDBX(rc, "SQLExecute", m_hstmt); ThrowDBX(rc, "SQLExecute", m_hstmt);
if (!Check(SQLNumResultCols(m_hstmt, &ncol)))
ThrowDBX(rc, "SQLNumResultCols", m_hstmt);
if (ncol) {
if (x) {
afrw = ncol;
strcpy(g->Message, "Result set column number");
} else {
// This should never happen while inserting
strcpy(g->Message, "Logical error while inserting");
} // endif ncol
} else {
// Insert, Update or Delete statement
if (!Check(SQLRowCount(m_hstmt, &afrw)))
ThrowDBX(rc, "SQLRowCount", m_hstmt);
if (x)
strcpy(g->Message, "Affected rows");
} // endif ncol
} catch(DBX *x) { } catch(DBX *x) {
strcpy(m_G->Message, x->GetErrorMessage(0)); strcpy(m_G->Message, x->GetErrorMessage(0));
SQLCancel(m_hstmt); SQLCancel(m_hstmt);
rc = SQLFreeStmt(m_hstmt, SQL_DROP); rc = SQLFreeStmt(m_hstmt, SQL_DROP);
m_hstmt = NULL; m_hstmt = NULL;
return true;
if (m_Transact) {
rc = SQLEndTran(SQL_HANDLE_DBC, m_hdbc, SQL_ROLLBACK);
m_Transact = false;
} // endif m_Transact
} // end try/catch } // end try/catch
return false; return (int)afrw;
} // end of ExecuteSQL } // end of ExecuteSQL
/***********************************************************************/ /***********************************************************************/
...@@ -1537,6 +1667,132 @@ bool ODBConn::BindParam(ODBCCOL *colp) ...@@ -1537,6 +1667,132 @@ bool ODBConn::BindParam(ODBCCOL *colp)
return false; return false;
} // end of BindParam } // end of BindParam
/**************************************************************************/
/* GetMetaData: constructs the result blocks containing the */
/* description of all the columns of an SQL command. */
/**************************************************************************/
PQRYRES ODBConn::GetMetaData(PGLOBAL g, char *dsn, char *src)
{
static int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_INT,
TYPE_SHORT, TYPE_SHORT};
static XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_PREC,
FLD_SCALE, FLD_NULL};
static unsigned int length[] = {0, 6, 10, 6, 6};
unsigned char cn[60];
int qcol = 5;
short nl, type, prec, nul, cns = (short)sizeof(cn);
PQRYRES qrp = NULL;
PCOLRES crp;
USHORT i;
SQLULEN n;
SWORD ncol;
RETCODE rc;
HSTMT hstmt;
if (Open(dsn, 10) < 1) // openReadOnly + noOdbcDialog
return NULL;
try {
rc = SQLAllocStmt(m_hdbc, &hstmt);
if (!Check(rc))
ThrowDBX(SQL_INVALID_HANDLE, "SQLAllocStmt");
OnSetOptions(hstmt);
do {
rc = SQLPrepare(hstmt, (PUCHAR)src, SQL_NTS);
// rc = SQLExecDirect(hstmt, (PUCHAR)src, SQL_NTS);
} while (rc == SQL_STILL_EXECUTING);
if (!Check(rc))
ThrowDBX(rc, "SQLExecDirect", hstmt);
do {
rc = SQLNumResultCols(hstmt, &ncol);
} while (rc == SQL_STILL_EXECUTING);
if (!Check(rc))
ThrowDBX(rc, "SQLNumResultCols", hstmt);
if (ncol) for (i = 1; i <= ncol; i++) {
do {
rc = SQLDescribeCol(hstmt, i, NULL, 0, &nl, NULL, NULL, NULL, NULL);
} while (rc == SQL_STILL_EXECUTING);
if (!Check(rc))
ThrowDBX(rc, "SQLDescribeCol", hstmt);
length[0] = max(length[0], (UINT)nl);
} // endfor i
} catch(DBX *x) {
strcpy(g->Message, x->GetErrorMessage(0));
goto err;
} // end try/catch
if (!ncol) {
strcpy(g->Message, "Invalid Srcdef");
goto err;
} // endif ncol
/************************************************************************/
/* Allocate the structures used to refer to the result set. */
/************************************************************************/
qrp = PlgAllocResult(g, qcol, ncol, IDS_COLUMNS + 3,
buftyp, fldtyp, length, false, true);
// Some columns must be renamed
for (i = 0, crp = qrp->Colresp; crp; crp = crp->Next)
switch (++i) {
case 3: crp->Name = "Precision"; break;
case 4: crp->Name = "Scale"; break;
case 5: crp->Name = "Nullable"; break;
} // endswitch i
/************************************************************************/
/* Now get the results into blocks. */
/************************************************************************/
try {
for (i = 0; i < ncol; i++) {
do {
rc = SQLDescribeCol(hstmt, i+1, cn, cns, &nl, &type, &n, &prec, &nul);
} while (rc == SQL_STILL_EXECUTING);
if (!Check(rc))
ThrowDBX(rc, "SQLDescribeCol", hstmt);
else
qrp->Nblin++;
crp = qrp->Colresp; // Column_Name
crp->Kdata->SetValue((char*)cn, i);
crp = crp->Next; // Data_Type
crp->Kdata->SetValue(type, i);
crp = crp->Next; // Precision (length)
crp->Kdata->SetValue((int)n, i);
crp = crp->Next; // Scale
crp->Kdata->SetValue(prec, i);
crp = crp->Next; // Nullable
crp->Kdata->SetValue(nul, i);
} // endfor i
} catch(DBX *x) {
strcpy(g->Message, x->GetErrorMessage(0));
qrp = NULL;
} // end try/catch
/* Cleanup */
err:
SQLCancel(hstmt);
rc = SQLFreeStmt(hstmt, SQL_DROP);
Close();
/************************************************************************/
/* Return the result pointer for use by GetData routines. */
/************************************************************************/
return qrp;
} // end of GetMetaData
/***********************************************************************/ /***********************************************************************/
/* Get the list of Data Sources and set it in qrp. */ /* Get the list of Data Sources and set it in qrp. */
/***********************************************************************/ /***********************************************************************/
...@@ -1840,6 +2096,11 @@ void ODBConn::Close() ...@@ -1840,6 +2096,11 @@ void ODBConn::Close()
} // endif m_hstmt } // endif m_hstmt
if (m_hdbc != SQL_NULL_HDBC) { if (m_hdbc != SQL_NULL_HDBC) {
if (m_Transact) {
rc = SQLEndTran(SQL_HANDLE_DBC, m_hdbc, SQL_COMMIT);
m_Transact = false;
} // endif m_Transact
rc = SQLDisconnect(m_hdbc); rc = SQLDisconnect(m_hdbc);
if (trace && rc != SQL_SUCCESS) if (trace && rc != SQL_SUCCESS)
......
...@@ -91,8 +91,7 @@ class DBX : public BLOCK { ...@@ -91,8 +91,7 @@ class DBX : public BLOCK {
// Implementation (use ThrowDBX to create) // Implementation (use ThrowDBX to create)
RETCODE GetRC(void) {return m_RC;} RETCODE GetRC(void) {return m_RC;}
PSZ GetMsg(void) {return m_Msg;} PSZ GetMsg(void) {return m_Msg;}
const char *GetErrorMessage(int i) const char *GetErrorMessage(int i);
{return (i >=0 && i < MAX_NUM_OF_MSG) ? m_ErrMsg[i] : "No ODBC error";}
protected: protected:
void BuildErrorMessage(ODBConn* pdb, HSTMT hstmt = SQL_NULL_HSTMT); void BuildErrorMessage(ODBConn* pdb, HSTMT hstmt = SQL_NULL_HSTMT);
...@@ -107,6 +106,7 @@ class DBX : public BLOCK { ...@@ -107,6 +106,7 @@ class DBX : public BLOCK {
/* ODBConn class. */ /* ODBConn class. */
/***********************************************************************/ /***********************************************************************/
class ODBConn : public BLOCK { class ODBConn : public BLOCK {
friend class TDBODBC;
friend class DBX; friend class DBX;
friend PQRYRES GetColumnInfo(PGLOBAL, char*&, char *, int, PVBLK&); friend PQRYRES GetColumnInfo(PGLOBAL, char*&, char *, int, PVBLK&);
private: private:
...@@ -142,11 +142,12 @@ class ODBConn : public BLOCK { ...@@ -142,11 +142,12 @@ class ODBConn : public BLOCK {
int ExecDirectSQL(char *sql, ODBCCOL *tocols); int ExecDirectSQL(char *sql, ODBCCOL *tocols);
int Fetch(void); int Fetch(void);
int PrepareSQL(char *sql); int PrepareSQL(char *sql);
bool ExecuteSQL(void); int ExecuteSQL(bool x);
bool BindParam(ODBCCOL *colp); bool BindParam(ODBCCOL *colp);
int GetCatInfo(CATPARM *cap); int GetCatInfo(CATPARM *cap);
bool GetDataSources(PQRYRES qrp); bool GetDataSources(PQRYRES qrp);
bool GetDrivers(PQRYRES qrp); bool GetDrivers(PQRYRES qrp);
PQRYRES GetMetaData(PGLOBAL g, char *dsn, char *src);
public: public:
// Set special options // Set special options
...@@ -185,5 +186,6 @@ class ODBConn : public BLOCK { ...@@ -185,5 +186,6 @@ class ODBConn : public BLOCK {
int m_Catver; int m_Catver;
PSZ m_Connect; PSZ m_Connect;
bool m_Updatable; bool m_Updatable;
bool m_Transact;
char m_IDQuoteChar; char m_IDQuoteChar;
}; // end of ODBConn class definition }; // end of ODBConn class definition
#ifndef _OS_H_INCLUDED #ifndef _OS_H_INCLUDED
#define _OS_H_INCLUDED #define _OS_H_INCLUDED
#if defined(__FreeBSD__) || defined(__APPLE__) #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__)
typedef off_t off64_t; typedef off_t off64_t;
#define lseek64(fd, offset, whence) lseek((fd), (offset), (whence)) #define lseek64(fd, offset, whence) lseek((fd), (offset), (whence))
#define open64(path, flags, mode) open((path), (flags), (mode)) #define open64(path, flags, mode) open((path), (flags), (mode))
......
...@@ -111,6 +111,7 @@ enum AMT {TYPE_AM_ERROR = 0, /* Type not defined */ ...@@ -111,6 +111,7 @@ enum AMT {TYPE_AM_ERROR = 0, /* Type not defined */
TYPE_AM_PIVOT = 120, /* PIVOT access method type no */ TYPE_AM_PIVOT = 120, /* PIVOT access method type no */
TYPE_AM_SRC = 121, /* PIVOT multiple column type no */ TYPE_AM_SRC = 121, /* PIVOT multiple column type no */
TYPE_AM_FNC = 122, /* PIVOT source column type no */ TYPE_AM_FNC = 122, /* PIVOT source column type no */
TYPE_AM_XML = 127, /* XML access method type no */
TYPE_AM_XTB = 130, /* SYS table access method type */ TYPE_AM_XTB = 130, /* SYS table access method type */
TYPE_AM_MAC = 137, /* MAC table access method type */ TYPE_AM_MAC = 137, /* MAC table access method type */
TYPE_AM_WMI = 139, /* WMI table access method type */ TYPE_AM_WMI = 139, /* WMI table access method type */
...@@ -582,5 +583,6 @@ FILE *global_fopen(GLOBAL *g, int msgid, const char *path, const char *mode); ...@@ -582,5 +583,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 global_open(GLOBAL *g, int msgid, const char *filename, int flags, int mode); int global_open(GLOBAL *g, int msgid, const char *filename, int flags, int mode);
DllExport LPCSTR PlugSetPath(LPSTR to, LPCSTR name, LPCSTR dir); DllExport LPCSTR PlugSetPath(LPSTR to, LPCSTR name, LPCSTR dir);
char *MakeEscape(PGLOBAL g, char* str, char q);
bool PushWarning(PGLOBAL, PTDBASE); bool PushWarning(PGLOBAL, PTDBASE);
...@@ -731,6 +731,34 @@ bool EvalLikePattern(LPCSTR sp, LPCSTR tp) ...@@ -731,6 +731,34 @@ bool EvalLikePattern(LPCSTR sp, LPCSTR tp)
return (b); return (b);
} /* end of EvalLikePattern */ } /* end of EvalLikePattern */
/***********************************************************************/
/* MakeEscape: Escape some characters in a string. */
/***********************************************************************/
char *MakeEscape(PGLOBAL g, char* str, char q)
{
char *bufp;
int i, k, n = 0, len = (int)strlen(str);
for (i = 0; i < len; i++)
if (str[i] == q || str[i] == '\\')
n++;
if (!n)
return str;
else
bufp = (char*)PlugSubAlloc(g, NULL, len + n + 1);
for (i = k = 0; i < len; i++) {
if (str[i] == q || str[i] == '\\')
bufp[k++] = '\\';
bufp[k++] = str[i];
} // endfor i
bufp[k] = 0;
return bufp;
} /* end of MakeEscape */
/***********************************************************************/ /***********************************************************************/
/* PlugConvertConstant: convert a Plug constant to an Xobject. */ /* PlugConvertConstant: convert a Plug constant to an Xobject. */
/***********************************************************************/ /***********************************************************************/
......
...@@ -147,6 +147,7 @@ class XMLNODELIST : public BLOCK { ...@@ -147,6 +147,7 @@ class XMLNODELIST : public BLOCK {
// Properties // Properties
virtual int GetLength(void) = 0; virtual int GetLength(void) = 0;
virtual PXNODE GetItem(PGLOBAL, int, PXNODE = NULL) = 0; virtual PXNODE GetItem(PGLOBAL, int, PXNODE = NULL) = 0;
virtual bool DropItem(PGLOBAL, int) = 0;
protected: protected:
// Constructor // Constructor
......
...@@ -93,7 +93,7 @@ PQRYRES CSVColumns(PGLOBAL g, const char *fn, char sep, char q, ...@@ -93,7 +93,7 @@ PQRYRES CSVColumns(PGLOBAL g, const char *fn, char sep, char q,
PCOLRES crp; PCOLRES crp;
if (info) { if (info) {
imax = 0; imax = hmax = 0;
length[0] = 128; length[0] = 128;
goto skipit; goto skipit;
} // endif info } // endif info
......
...@@ -884,9 +884,11 @@ void TDBDIR::CloseDB(PGLOBAL g) ...@@ -884,9 +884,11 @@ void TDBDIR::CloseDB(PGLOBAL g)
_findclose(Hsearch); _findclose(Hsearch);
Hsearch = -1; Hsearch = -1;
#else // !WIN32 #else // !WIN32
// Close the DIR handle. // Close the DIR handle
closedir(Dir); if (Dir) {
Dir = NULL; closedir(Dir);
Dir = NULL;
} // endif dir
#endif // !WIN32 #endif // !WIN32
iFile = 0; iFile = 0;
} // end of CloseDB } // end of CloseDB
......
...@@ -86,6 +86,7 @@ MYSQLDEF::MYSQLDEF(void) ...@@ -86,6 +86,7 @@ MYSQLDEF::MYSQLDEF(void)
Isview = FALSE; Isview = FALSE;
Bind = FALSE; Bind = FALSE;
Delayed = FALSE; Delayed = FALSE;
Xsrc = FALSE;
} // end of MYSQLDEF constructor } // end of MYSQLDEF constructor
/***********************************************************************/ /***********************************************************************/
...@@ -171,7 +172,7 @@ bool MYSQLDEF::GetServerInfo(PGLOBAL g, const char *server_name) ...@@ -171,7 +172,7 @@ bool MYSQLDEF::GetServerInfo(PGLOBAL g, const char *server_name)
/* true error */ /* true error */
/* */ /* */
/***********************************************************************/ /***********************************************************************/
bool MYSQLDEF::ParseURL(PGLOBAL g, char *url) bool MYSQLDEF::ParseURL(PGLOBAL g, char *url, bool b)
{ {
if ((!strstr(url, "://") && (!strchr(url, '@')))) { if ((!strstr(url, "://") && (!strchr(url, '@')))) {
// No :// or @ in connection string. Must be a straight // No :// or @ in connection string. Must be a straight
...@@ -248,34 +249,41 @@ bool MYSQLDEF::ParseURL(PGLOBAL g, char *url) ...@@ -248,34 +249,41 @@ bool MYSQLDEF::ParseURL(PGLOBAL g, char *url)
if ((Database = strchr(Hostname, '/'))) { if ((Database = strchr(Hostname, '/'))) {
*Database++ = 0; *Database++ = 0;
if ((Tabname = strchr(Database, '/'))) if ((Tabname = strchr(Database, '/'))) {
*Tabname++ = 0; *Tabname++ = 0;
// Make sure there's not an extra / // Make sure there's not an extra /
if ((strchr(Tabname, '/'))) { if ((strchr(Tabname, '/'))) {
strcpy(g->Message, "Syntax error in URL"); strcpy(g->Message, "Syntax error in URL");
return true; return true;
} // endif / } // endif /
} // endif Tabname
} // endif database } // endif database
if ((sport = strchr(Hostname, ':'))) if ((sport = strchr(Hostname, ':')))
*sport++ = 0; *sport++ = 0;
Portnumber = (sport && sport[0]) ? atoi(sport) : GetDefaultPort(); // For unspecified values, get the values of old style options
// but only if called from MYSQLDEF, else set them to NULL
Portnumber = (sport && sport[0]) ? atoi(sport)
: (b) ? Cat->GetIntCatInfo("Port", GetDefaultPort()) : 0;
if (Username[0] == 0) if (Username[0] == 0)
Username = Cat->GetStringCatInfo(g, "User", "*"); Username = (b) ? Cat->GetStringCatInfo(g, "User", "*") : NULL;
if (Hostname[0] == 0) if (Hostname[0] == 0)
Hostname = Cat->GetStringCatInfo(g, "Host", "localhost"); Hostname = (b) ? Cat->GetStringCatInfo(g, "Host", "localhost") : NULL;
if (!Database || !*Database) if (!Database || !*Database)
Database = Cat->GetStringCatInfo(g, "Database", "*"); Database = (b) ? Cat->GetStringCatInfo(g, "Database", "*") : NULL;
if (!Tabname || !*Tabname) if (!Tabname || !*Tabname)
Tabname = Name; Tabname = (b) ? Cat->GetStringCatInfo(g, "Tabname", Name) : NULL;
if (!Password)
Password = (b) ? Cat->GetStringCatInfo(g, "Password", NULL) : NULL;
} // endif URL } // endif URL
#if 0 #if 0
...@@ -347,6 +355,7 @@ bool MYSQLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) ...@@ -347,6 +355,7 @@ bool MYSQLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
if ((Srcdef = Cat->GetStringCatInfo(g, "Srcdef", NULL))) if ((Srcdef = Cat->GetStringCatInfo(g, "Srcdef", NULL)))
Isview = TRUE; Isview = TRUE;
Xsrc = Cat->GetBoolCatInfo("Execsrc", FALSE);
return FALSE; return FALSE;
} // end of DefineAM } // end of DefineAM
...@@ -355,7 +364,9 @@ bool MYSQLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) ...@@ -355,7 +364,9 @@ bool MYSQLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
/***********************************************************************/ /***********************************************************************/
PTDB MYSQLDEF::GetTable(PGLOBAL g, MODE m) PTDB MYSQLDEF::GetTable(PGLOBAL g, MODE m)
{ {
if (Catfunc == FNC_COL) if (Xsrc)
return new(g) TDBMYEXC(this);
else if (Catfunc == FNC_COL)
return new(g) TDBMCL(this); return new(g) TDBMCL(this);
else else
return new(g) TDBMYSQL(this); return new(g) TDBMYSQL(this);
...@@ -507,6 +518,9 @@ bool TDBMYSQL::MakeSelect(PGLOBAL g) ...@@ -507,6 +518,9 @@ bool TDBMYSQL::MakeSelect(PGLOBAL g)
if (To_Filter) if (To_Filter)
strcat(strcat(Query, " WHERE "), To_Filter); strcat(strcat(Query, " WHERE "), To_Filter);
if (trace)
htrc("Query=%s\n", Query);
// Now we know how much to suballocate // Now we know how much to suballocate
PlugSubAlloc(g, NULL, strlen(Query) + 1); PlugSubAlloc(g, NULL, strlen(Query) + 1);
return FALSE; return FALSE;
...@@ -1040,18 +1054,20 @@ int TDBMYSQL::DeleteDB(PGLOBAL g, int irc) ...@@ -1040,18 +1054,20 @@ int TDBMYSQL::DeleteDB(PGLOBAL g, int irc)
/***********************************************************************/ /***********************************************************************/
void TDBMYSQL::CloseDB(PGLOBAL g) void TDBMYSQL::CloseDB(PGLOBAL g)
{ {
if (Mode == MODE_INSERT) { if (Myc.Connected()) {
char cmd[64]; if (Mode == MODE_INSERT) {
int w; char cmd[64];
PDBUSER dup = PlgGetUser(g); int w;
PDBUSER dup = PlgGetUser(g);
dup->Step = "Enabling indexes"; dup->Step = "Enabling indexes";
sprintf(cmd, "ALTER TABLE `%s` ENABLE KEYS", Tabname); sprintf(cmd, "ALTER TABLE `%s` ENABLE KEYS", Tabname);
Myc.m_Rows = -1; // To execute the query Myc.m_Rows = -1; // To execute the query
m_Rc = Myc.ExecSQL(g, cmd, &w); m_Rc = Myc.ExecSQL(g, cmd, &w);
} // endif m_Rc } // endif m_Rc
Myc.Close(); Myc.Close();
} // endif Myc
if (trace) if (trace)
htrc("MySQL CloseDB: closing %s rc=%d\n", Name, m_Rc); htrc("MySQL CloseDB: closing %s rc=%d\n", Name, m_Rc);
...@@ -1275,6 +1291,212 @@ void MYSQLCOL::WriteColumn(PGLOBAL g) ...@@ -1275,6 +1291,212 @@ void MYSQLCOL::WriteColumn(PGLOBAL g)
} // end of WriteColumn } // end of WriteColumn
/* ------------------------------------------------------------------- */
/***********************************************************************/
/* Implementation of the TDBMYSQL class. */
/***********************************************************************/
// Is this really useful ???
PTDB TDBMYEXC::CopyOne(PTABS t)
{
PTDB tp;
PCOL cp1, cp2;
PGLOBAL g = t->G;
tp = new(g) TDBMYEXC(g, this);
for (cp1 = Columns; cp1; cp1 = cp1->GetNext()) {
cp2 = new(g) MYXCOL((PMYXCOL)cp1, tp);
NewPointer(t, cp1, cp2);
} // endfor cp1
return tp;
} // end of CopyOne
/***********************************************************************/
/* Allocate MYSQL column description block. */
/***********************************************************************/
PCOL TDBMYEXC::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
{
PMYXCOL colp = new(g) MYXCOL(cdp, this, cprec, n);
if (!colp->Flag)
Cmdcol = colp->GetName();
return colp;
} // end of MakeCol
/***********************************************************************/
/* MakeCMD: make the SQL statement to send to MYSQL connection. */
/***********************************************************************/
char *TDBMYEXC::MakeCMD(PGLOBAL g)
{
char *xcmd = NULL;
if (To_Filter) {
if (Cmdcol) {
char col[128], cmd[1024];
int n;
memset(cmd, 0, sizeof(cmd));
n = sscanf(To_Filter, "%s = '%1023c", col, cmd);
if (n == 2 && !stricmp(col, Cmdcol)) {
xcmd = (char*)PlugSubAlloc(g, NULL, strlen(cmd) + 1);
strcpy(xcmd, cmd);
xcmd[strlen(xcmd) - 1] = 0;
} else
strcpy(g->Message, "Invalid command specification filter");
} else
strcpy(g->Message, "No command column in select list");
} else if (!Srcdef)
strcpy(g->Message, "No Srcdef default command");
else
xcmd = Srcdef;
return xcmd;
} // end of MakeCMD
/***********************************************************************/
/* EXC GetMaxSize: returns the maximum number of rows in the table. */
/***********************************************************************/
int TDBMYEXC::GetMaxSize(PGLOBAL g)
{
if (MaxSize < 0) {
MaxSize = 1;
} // endif MaxSize
return MaxSize;
} // end of GetMaxSize
/***********************************************************************/
/* MySQL Exec Access Method opening routine. */
/***********************************************************************/
bool TDBMYEXC::OpenDB(PGLOBAL g)
{
int rc;
if (Use == USE_OPEN) {
strcpy(g->Message, "Multiple execution is not allowed");
return true;
} // endif use
/*********************************************************************/
/* Open a MySQL connection for this table. */
/* Note: this may not be the proper way to do. Perhaps it is better */
/* to test whether a connection is already open for this server */
/* and if so to allocate just a new result set. But this only for */
/* servers allowing concurency in getting results ??? */
/*********************************************************************/
if (!Myc.Connected())
if (Myc.Open(g, Host, Database, User, Pwd, Port))
return true;
Use = USE_OPEN; // Do it now in case we are recursively called
if (Mode != MODE_READ) {
strcpy(g->Message, "No INSERT/DELETE/UPDATE of MYSQL EXEC tables");
return true;
} // endif Mode
/*********************************************************************/
/* Get the command to execute. */
/*********************************************************************/
if (!(Query = MakeCMD(g))) {
Myc.Close();
return true;
} // endif Query
if ((rc = Myc.ExecSQL(g, Query)) == RC_NF) {
strcpy(g->Message, "Affected rows");
AftRows = Myc.m_Rows;
} else if (rc == RC_OK) {
sprintf(g->Message, "Columns and %d rows", Myc.m_Rows);
AftRows = Myc.m_Fields;
} else
return true;
return false;
} // end of OpenDB
/***********************************************************************/
/* Data Base read routine for MYSQL access method. */
/***********************************************************************/
int TDBMYEXC::ReadDB(PGLOBAL g)
{
return (++N) ? RC_EF : RC_OK;
} // end of ReadDB
/***********************************************************************/
/* WriteDB: Data Base write routine for Exec MYSQL access methods. */
/***********************************************************************/
int TDBMYEXC::WriteDB(PGLOBAL g)
{
strcpy(g->Message, "EXEC MYSQL tables are read only");
return RC_FX;
} // end of WriteDB
// ------------------------- MYXCOL functions ---------------------------
/***********************************************************************/
/* MYXCOL public constructor. */
/***********************************************************************/
MYXCOL::MYXCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am)
: MYSQLCOL(cdp, tdbp, cprec, i, am)
{
// Set additional EXEC MYSQL access method information for column.
Flag = cdp->GetOffset();
} // end of MYSQLCOL constructor
/***********************************************************************/
/* MYSQLCOL public constructor. */
/***********************************************************************/
MYXCOL::MYXCOL(MYSQL_FIELD *fld, PTDB tdbp, int i, PSZ am)
: MYSQLCOL(fld, tdbp, i, am)
{
if (trace)
htrc(" making new %sCOL C%d %s at %p\n", am, Index, Name, this);
} // end of MYSQLCOL constructor
/***********************************************************************/
/* MYXCOL constructor used for copying columns. */
/* tdbp is the pointer to the new table descriptor. */
/***********************************************************************/
MYXCOL::MYXCOL(MYXCOL *col1, PTDB tdbp) : MYSQLCOL(col1, tdbp)
{
Flag = col1->Flag;
} // end of MYXCOL copy constructor
/***********************************************************************/
/* ReadColumn: */
/***********************************************************************/
void MYXCOL::ReadColumn(PGLOBAL g)
{
PTDBMYX tdbp = (PTDBMYX)To_Tdb;
switch (Flag) {
case 0: Value->SetValue_psz(tdbp->Query); break;
case 1: Value->SetValue(tdbp->AftRows); break;
case 2: Value->SetValue_psz(g->Message); break;
default: Value->SetValue_psz("Invalid Flag"); break;
} // endswitch Flag
} // end of ReadColumn
/***********************************************************************/
/* WriteColumn: should never be called. */
/***********************************************************************/
void MYXCOL::WriteColumn(PGLOBAL g)
{
assert(false);
} // end of WriteColumn
/* ---------------------------TDBMCL class --------------------------- */ /* ---------------------------TDBMCL class --------------------------- */
/***********************************************************************/ /***********************************************************************/
......
...@@ -3,8 +3,10 @@ ...@@ -3,8 +3,10 @@
typedef class MYSQLDEF *PMYDEF; typedef class MYSQLDEF *PMYDEF;
typedef class TDBMYSQL *PTDBMY; typedef class TDBMYSQL *PTDBMY;
typedef class MYSQLC *PMYC;
typedef class MYSQLCOL *PMYCOL; typedef class MYSQLCOL *PMYCOL;
typedef class TDBMYEXC *PTDBMYX;
typedef class MYXCOL *PMYXCOL;
typedef class MYSQLC *PMYC;
/* ------------------------- MYSQL classes --------------------------- */ /* ------------------------- MYSQL classes --------------------------- */
...@@ -38,7 +40,7 @@ class MYSQLDEF : public TABDEF {/* Logical table description */ ...@@ -38,7 +40,7 @@ class MYSQLDEF : public TABDEF {/* Logical table description */
// Methods // Methods
virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff); virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
virtual PTDB GetTable(PGLOBAL g, MODE m); virtual PTDB GetTable(PGLOBAL g, MODE m);
bool ParseURL(PGLOBAL g, char *url); bool ParseURL(PGLOBAL g, char *url, bool b = true);
bool GetServerInfo(PGLOBAL g, const char *server_name); bool GetServerInfo(PGLOBAL g, const char *server_name);
protected: protected:
...@@ -54,6 +56,7 @@ class MYSQLDEF : public TABDEF {/* Logical table description */ ...@@ -54,6 +56,7 @@ class MYSQLDEF : public TABDEF {/* Logical table description */
bool Isview; /* TRUE if this table is a MySQL view */ bool Isview; /* TRUE if this table is a MySQL view */
bool Bind; /* Use prepared statement on insert */ bool Bind; /* Use prepared statement on insert */
bool Delayed; /* Delayed insert */ bool Delayed; /* Delayed insert */
bool Xsrc; /* Execution type */
}; // end of MYSQLDEF }; // end of MYSQLDEF
/***********************************************************************/ /***********************************************************************/
...@@ -158,6 +161,87 @@ class MYSQLCOL : public COLBLK { ...@@ -158,6 +161,87 @@ class MYSQLCOL : public COLBLK {
int Rank; // Rank (position) number in the query int Rank; // Rank (position) number in the query
}; // end of class MYSQLCOL }; // end of class MYSQLCOL
/***********************************************************************/
/* This is the class declaration for the exec command MYSQL table. */
/***********************************************************************/
class TDBMYEXC : public TDBMYSQL {
friend class MYXCOL;
public:
// Constructor
TDBMYEXC(PMYDEF tdp) : TDBMYSQL(tdp) {Cmdcol = NULL;}
TDBMYEXC(PGLOBAL g, PTDBMYX tdbp) : TDBMYSQL(g, tdbp)
{Cmdcol = tdbp->Cmdcol;}
// Implementation
//virtual AMT GetAmType(void) {return TYPE_AM_MYSQL;}
virtual PTDB Duplicate(PGLOBAL g) {return (PTDB)new(g) TDBMYEXC(g, this);}
// Methods
virtual PTDB CopyOne(PTABS t);
//virtual int GetAffectedRows(void) {return AftRows;}
//virtual int GetRecpos(void) {return N;}
//virtual int GetProgMax(PGLOBAL g);
//virtual void ResetDB(void) {N = 0;}
//virtual int RowNumber(PGLOBAL g, bool b = FALSE);
virtual bool IsView(void) {return Isview;}
//virtual PSZ GetServer(void) {return Server;}
// void SetDatabase(LPCSTR db) {Database = (char*)db;}
// Database routines
virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
virtual int GetMaxSize(PGLOBAL g);
virtual bool OpenDB(PGLOBAL g);
virtual int ReadDB(PGLOBAL g);
virtual int WriteDB(PGLOBAL g);
//virtual int DeleteDB(PGLOBAL g, int irc);
//virtual void CloseDB(PGLOBAL g);
// Specific routines
// bool SetColumnRanks(PGLOBAL g);
// PCOL MakeFieldColumn(PGLOBAL g, char *name);
// PSZ FindFieldColumn(char *name);
protected:
// Internal functions
char *MakeCMD(PGLOBAL g);
//bool MakeSelect(PGLOBAL g);
//bool MakeInsert(PGLOBAL g);
//int BindColumns(PGLOBAL g);
// Members
char *Cmdcol; // The name of the Xsrc command column
}; // end of class TDBMYEXC
/***********************************************************************/
/* Class MYXCOL: MySQL exec command table column. */
/***********************************************************************/
class MYXCOL : public MYSQLCOL {
friend class TDBMYEXC;
public:
// Constructors
MYXCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am = "MYSQL");
MYXCOL(MYSQL_FIELD *fld, PTDB tdbp, int i, PSZ am = "MYSQL");
MYXCOL(MYXCOL *colp, PTDB tdbp); // Constructor used in copy process
// Implementation
//virtual int GetAmType(void) {return TYPE_AM_MYSQL;}
// void InitBind(PGLOBAL g);
// Methods
//virtual bool SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check);
virtual void ReadColumn(PGLOBAL g);
virtual void WriteColumn(PGLOBAL g);
// bool FindRank(PGLOBAL g);
protected:
// Default constructor not to be used
MYXCOL(void) {}
// Members
char *Buffer; // To get returned message
int Flag; // Column content desc
}; // end of class MYXCOL
/***********************************************************************/ /***********************************************************************/
/* This is the class declaration for the MYSQL column catalog table. */ /* This is the class declaration for the MYSQL column catalog table. */
/***********************************************************************/ /***********************************************************************/
......
/************* Tabodbc C++ Program Source Code File (.CPP) *************/ /************* Tabodbc C++ Program Source Code File (.CPP) *************/
/* PROGRAM NAME: TABODBC */ /* PROGRAM NAME: TABODBC */
/* ------------- */ /* ------------- */
/* Version 2.5 */ /* Version 2.6 */
/* */ /* */
/* COPYRIGHT: */ /* COPYRIGHT: */
/* ---------- */ /* ---------- */
...@@ -90,8 +90,9 @@ extern int num_read, num_there, num_eq[2]; // Statistics ...@@ -90,8 +90,9 @@ extern int num_read, num_there, num_eq[2]; // Statistics
/***********************************************************************/ /***********************************************************************/
ODBCDEF::ODBCDEF(void) ODBCDEF::ODBCDEF(void)
{ {
Connect = Tabname = Tabowner = Tabqual = Qchar = NULL; Connect = Tabname = Tabowner = Tabqual = Srcdef = Qchar = NULL;
Catver = Options = 0; Catver = Options = 0;
Xsrc = false;
} // end of ODBCDEF constructor } // end of ODBCDEF constructor
/***********************************************************************/ /***********************************************************************/
...@@ -99,17 +100,17 @@ ODBCDEF::ODBCDEF(void) ...@@ -99,17 +100,17 @@ ODBCDEF::ODBCDEF(void)
/***********************************************************************/ /***********************************************************************/
bool ODBCDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) bool ODBCDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
{ {
int dop = ODBConn::noOdbcDialog; // Default for options
Desc = Connect = Cat->GetStringCatInfo(g, "Connect", ""); Desc = Connect = Cat->GetStringCatInfo(g, "Connect", "");
Tabname = Cat->GetStringCatInfo(g, "Name", Tabname = Cat->GetStringCatInfo(g, "Name",
(Catfunc & (FNC_TABLE | FNC_COL)) ? NULL : Name); (Catfunc & (FNC_TABLE | FNC_COL)) ? NULL : Name);
Tabname = Cat->GetStringCatInfo(g, "Tabname", Tabname); Tabname = Cat->GetStringCatInfo(g, "Tabname", Tabname);
Tabowner = Cat->GetStringCatInfo(g, "Owner", ""); Tabowner = Cat->GetStringCatInfo(g, "Owner", "");
Tabqual = Cat->GetStringCatInfo(g, "Qualifier", ""); Tabqual = Cat->GetStringCatInfo(g, "Qualifier", "");
Srcdef = Cat->GetStringCatInfo(g, "Srcdef", NULL);
Qchar = Cat->GetStringCatInfo(g, "Qchar", ""); Qchar = Cat->GetStringCatInfo(g, "Qchar", "");
Catver = Cat->GetIntCatInfo("Catver", 2); Catver = Cat->GetIntCatInfo("Catver", 2);
Options = Cat->GetIntCatInfo("Options", dop); Xsrc = Cat->GetBoolCatInfo("Execsrc", FALSE);
Options = ODBConn::noOdbcDialog;
Pseudo = 2; // FILID is Ok but not ROWID Pseudo = 2; // FILID is Ok but not ROWID
return false; return false;
} // end of DefineAM } // end of DefineAM
...@@ -125,7 +126,9 @@ PTDB ODBCDEF::GetTable(PGLOBAL g, MODE m) ...@@ -125,7 +126,9 @@ PTDB ODBCDEF::GetTable(PGLOBAL g, MODE m)
/* Allocate a TDB of the proper type. */ /* Allocate a TDB of the proper type. */
/* Column blocks will be allocated only when needed. */ /* Column blocks will be allocated only when needed. */
/*********************************************************************/ /*********************************************************************/
switch (Catfunc) { if (Xsrc)
tdbp = new(g) TDBXDBC(this);
else switch (Catfunc) {
case FNC_COL: case FNC_COL:
tdbp = new(g) TDBOCL(this); tdbp = new(g) TDBOCL(this);
break; break;
...@@ -161,19 +164,21 @@ TDBODBC::TDBODBC(PODEF tdp) : TDBASE(tdp) ...@@ -161,19 +164,21 @@ TDBODBC::TDBODBC(PODEF tdp) : TDBASE(tdp)
Cnp = NULL; Cnp = NULL;
if (tdp) { if (tdp) {
Connect = tdp->GetConnect(); Connect = tdp->Connect;
TableName = tdp->GetTabname(); TableName = tdp->Tabname;
Owner = tdp->GetTabowner(); Owner = tdp->Tabowner;
Qualifier = tdp->GetTabqual(); Qualifier = tdp->Tabqual;
Srcdef = tdp->Srcdef;
Quote = tdp->GetQchar(); Quote = tdp->GetQchar();
Options = tdp->GetOptions(); Options = tdp->Options;
Rows = tdp->GetElemt(); Rows = tdp->GetElemt();
Catver = tdp->GetCatver(); Catver = tdp->Catver;
} else { } else {
Connect = NULL; Connect = NULL;
TableName = NULL; TableName = NULL;
Owner = NULL; Owner = NULL;
Qualifier = NULL; Qualifier = NULL;
Srcdef = NULL;
Quote = NULL; Quote = NULL;
Options = 0; Options = 0;
Rows = 0; Rows = 0;
...@@ -201,6 +206,7 @@ TDBODBC::TDBODBC(PTDBODBC tdbp) : TDBASE(tdbp) ...@@ -201,6 +206,7 @@ TDBODBC::TDBODBC(PTDBODBC tdbp) : TDBASE(tdbp)
TableName = tdbp->TableName; TableName = tdbp->TableName;
Owner = tdbp->Owner; Owner = tdbp->Owner;
Qualifier = tdbp->Qualifier; Qualifier = tdbp->Qualifier;
Srcdef = tdbp->Srcdef;
Quote = tdbp->Quote; Quote = tdbp->Quote;
Query = tdbp->Query; Query = tdbp->Query;
Count = tdbp->Count; Count = tdbp->Count;
...@@ -299,7 +305,6 @@ void TDBODBC::SetFile(PGLOBAL g, PSZ fn) ...@@ -299,7 +305,6 @@ void TDBODBC::SetFile(PGLOBAL g, PSZ fn)
DBQ = fn; DBQ = fn;
} // end of SetFile } // end of SetFile
/******************************************************************/ /******************************************************************/
/* Convert an UTF-8 string to latin characters. */ /* Convert an UTF-8 string to latin characters. */
/******************************************************************/ /******************************************************************/
...@@ -314,7 +319,6 @@ int TDBODBC::Decode(char *txt, char *buf, size_t n) ...@@ -314,7 +319,6 @@ int TDBODBC::Decode(char *txt, char *buf, size_t n)
return 0; return 0;
} // end of Decode } // end of Decode
/***********************************************************************/ /***********************************************************************/
/* MakeSQL: make the SQL statement use with ODBC connection. */ /* MakeSQL: make the SQL statement use with ODBC connection. */
/* Note: when implementing EOM filtering, column only used in local */ /* Note: when implementing EOM filtering, column only used in local */
...@@ -329,6 +333,9 @@ char *TDBODBC::MakeSQL(PGLOBAL g, bool cnt) ...@@ -329,6 +333,9 @@ char *TDBODBC::MakeSQL(PGLOBAL g, bool cnt)
PTABLE tablep = To_Table; PTABLE tablep = To_Table;
PCOL colp; PCOL colp;
if (Srcdef)
return Srcdef;
if (!cnt) { if (!cnt) {
// Normal SQL statement to retrieve results // Normal SQL statement to retrieve results
for (colp = Columns; colp; colp = colp->GetNext()) for (colp = Columns; colp; colp = colp->GetNext())
...@@ -430,6 +437,83 @@ char *TDBODBC::MakeSQL(PGLOBAL g, bool cnt) ...@@ -430,6 +437,83 @@ char *TDBODBC::MakeSQL(PGLOBAL g, bool cnt)
return sql; return sql;
} // end of MakeSQL } // end of MakeSQL
/***********************************************************************/
/* MakeInsert: make the Insert statement used with ODBC connection. */
/***********************************************************************/
bool TDBODBC::MakeInsert(PGLOBAL g)
{
char *colist, *valist;
// char *tk = "`";
int len = 0;
bool b = FALSE;
PCOL colp;
if (Query)
return false; // already done
for (colp = Columns; colp; colp = colp->GetNext())
if (colp->IsSpecial()) {
strcpy(g->Message, MSG(NO_ODBC_SPECOL));
return true;
} else {
len += (strlen(colp->GetName()) + 4);
((PODBCCOL)colp)->Rank = ++Nparm;
} // endif colp
colist = (char*)PlugSubAlloc(g, NULL, len);
*colist = '\0';
valist = (char*)PlugSubAlloc(g, NULL, 2 * Nparm);
*valist = '\0';
for (colp = Columns; colp; colp = colp->GetNext()) {
if (b) {
strcat(colist, ", ");
strcat(valist, ",");
} else
b = true;
if (Quote)
strcat(strcat(strcat(colist, Quote), colp->GetName()), Quote);
else
strcat(colist, colp->GetName());
strcat(valist, "?"); // Parameter marker
} // endfor colp
// Below 32 is enough to contain the fixed part of the query
len = (strlen(TableName) + strlen(colist) + strlen(valist) + 32);
Query = (char*)PlugSubAlloc(g, NULL, len);
strcpy(Query, "INSERT INTO ");
if (Quote)
strcat(strcat(strcat(Query, Quote), TableName), Quote);
else
strcat(Query, TableName);
strcat(strcat(strcat(Query, " ("), colist), ") VALUES (");
strcat(strcat(Query, valist), ")");
return false;
} // end of MakeInsert
/***********************************************************************/
/* ODBC Bind Parameter function. */
/***********************************************************************/
bool TDBODBC::BindParameters(PGLOBAL g)
{
PODBCCOL colp;
for (colp = (PODBCCOL)Columns; colp; colp = (PODBCCOL)colp->Next) {
colp->AllocateBuffers(g, 0);
if (Ocp->BindParam(colp))
return true;
} // endfor colp
return false;
} // end of BindParameters
/***********************************************************************/ /***********************************************************************/
/* ResetSize: call by TDBMUL when calculating size estimate. */ /* ResetSize: call by TDBMUL when calculating size estimate. */
/***********************************************************************/ /***********************************************************************/
...@@ -448,6 +532,16 @@ void TDBODBC::ResetSize(void) ...@@ -448,6 +532,16 @@ void TDBODBC::ResetSize(void)
int TDBODBC::GetMaxSize(PGLOBAL g) int TDBODBC::GetMaxSize(PGLOBAL g)
{ {
if (MaxSize < 0) { if (MaxSize < 0) {
// Make MariaDB happy
MaxSize = 100;
#if 0
// This is unuseful and takes time
if (Srcdef) {
// Return a reasonable guess
MaxSize = 100;
return MaxSize;
} // endif Srcdef
if (!Ocp) if (!Ocp)
Ocp = new(g) ODBConn(g, this); Ocp = new(g) ODBConn(g, this);
...@@ -466,19 +560,18 @@ int TDBODBC::GetMaxSize(PGLOBAL g) ...@@ -466,19 +560,18 @@ int TDBODBC::GetMaxSize(PGLOBAL g)
if ((MaxSize = Ocp->GetResultSize(Count, Cnp)) < 0) if ((MaxSize = Ocp->GetResultSize(Count, Cnp)) < 0)
return -3; return -3;
#endif // 0
} // endif MaxSize } // endif MaxSize
return MaxSize; return MaxSize;
} // end of GetMaxSize } // end of GetMaxSize
/***********************************************************************/ /***********************************************************************/
/* Return 0 in mode DELETE or UPDATE to tell that it is done. */ /* Return max size value. */
/***********************************************************************/ /***********************************************************************/
int TDBODBC::GetProgMax(PGLOBAL g) int TDBODBC::GetProgMax(PGLOBAL g)
{ {
return (Mode == MODE_DELETE || Mode == MODE_UPDATE) ? 0 return GetMaxSize(g);
: GetMaxSize(g);
} // end of GetProgMax } // end of GetProgMax
/***********************************************************************/ /***********************************************************************/
...@@ -546,14 +639,24 @@ bool TDBODBC::OpenDB(PGLOBAL g) ...@@ -546,14 +639,24 @@ bool TDBODBC::OpenDB(PGLOBAL g)
if (!colp->IsSpecial()) if (!colp->IsSpecial())
colp->AllocateBuffers(g, Rows); colp->AllocateBuffers(g, Rows);
} else } else {
rc = true; Ocp->Close();
return true;
} // endif Query
if (!rc) if (!rc)
rc = ((Rows = Ocp->ExecDirectSQL(Query, (PODBCCOL)Columns)) < 0); rc = ((Rows = Ocp->ExecDirectSQL(Query, (PODBCCOL)Columns)) < 0);
} else if (Mode == MODE_INSERT) {
if (!(rc = MakeInsert(g)))
if (Nparm != Ocp->PrepareSQL(Query)) {
strcpy(g->Message, MSG(PARM_CNT_MISS));
rc = true;
} else
rc = BindParameters(g);
} else { } else {
strcpy(g->Message, "ODBC tables are read only in this version"); strcpy(g->Message, "No DELETE/UPDATE of ODBC tablesd");
return true; return true;
} // endelse } // endelse
...@@ -592,30 +695,6 @@ int TDBODBC::ReadDB(PGLOBAL g) ...@@ -592,30 +695,6 @@ int TDBODBC::ReadDB(PGLOBAL g)
// Direct access of ODBC tables is not implemented yet // Direct access of ODBC tables is not implemented yet
strcpy(g->Message, MSG(NO_ODBC_DIRECT)); strcpy(g->Message, MSG(NO_ODBC_DIRECT));
longjmp(g->jumper[g->jump_level], GetAmType()); longjmp(g->jumper[g->jump_level], GetAmType());
#if 0
/*******************************************************************/
/* Reading is by an index table. */
/*******************************************************************/
int recpos = To_Kindex->Fetch(g);
switch (recpos) {
case -1: // End of file reached
return RC_EF;
case -2: // No match for join
return RC_NF;
case -3: // Same record as current one
num_there++;
return RC_OK;
default:
/***************************************************************/
/* Set the cursor position according to record to read. */
/***************************************************************/
//--------------------------------- TODO --------------------------------
break;
} // endswitch recpos
#endif // 0
} // endif To_Kindex } // endif To_Kindex
/*********************************************************************/ /*********************************************************************/
...@@ -641,8 +720,15 @@ int TDBODBC::ReadDB(PGLOBAL g) ...@@ -641,8 +720,15 @@ int TDBODBC::ReadDB(PGLOBAL g)
/***********************************************************************/ /***********************************************************************/
int TDBODBC::WriteDB(PGLOBAL g) int TDBODBC::WriteDB(PGLOBAL g)
{ {
strcpy(g->Message, "ODBC tables are read only"); int n = Ocp->ExecuteSQL(false);
return RC_FX;
if (n < 0) {
AftRows = n;
return RC_FX;
} else
AftRows += n;
return RC_OK;
} // end of WriteDB } // end of WriteDB
/***********************************************************************/ /***********************************************************************/
...@@ -664,7 +750,8 @@ void TDBODBC::CloseDB(PGLOBAL g) ...@@ -664,7 +750,8 @@ void TDBODBC::CloseDB(PGLOBAL g)
// To_Kindex = NULL; // To_Kindex = NULL;
// } // endif // } // endif
Ocp->Close(); if (Ocp)
Ocp->Close();
if (trace) if (trace)
htrc("ODBC CloseDB: closing %s\n", Name); htrc("ODBC CloseDB: closing %s\n", Name);
...@@ -892,7 +979,7 @@ void ODBCCOL::WriteColumn(PGLOBAL g) ...@@ -892,7 +979,7 @@ void ODBCCOL::WriteColumn(PGLOBAL g)
/* Do convert the column value if necessary. */ /* Do convert the column value if necessary. */
/*********************************************************************/ /*********************************************************************/
if (Value != To_Val) if (Value != To_Val)
Value->SetValue_pval(To_Val, false); // Convert the inserted value Value->SetValue_pval(To_Val, FALSE); // Convert the inserted value
if (Buf_Type == TYPE_DATE) { if (Buf_Type == TYPE_DATE) {
struct tm tm, *dbtime = ((DTVAL*)Value)->GetGmTime(&tm); struct tm tm, *dbtime = ((DTVAL*)Value)->GetGmTime(&tm);
...@@ -903,8 +990,245 @@ void ODBCCOL::WriteColumn(PGLOBAL g) ...@@ -903,8 +990,245 @@ void ODBCCOL::WriteColumn(PGLOBAL g)
Sqlbuf->day = dbtime->tm_mday; Sqlbuf->day = dbtime->tm_mday;
Sqlbuf->month = dbtime->tm_mon + 1; Sqlbuf->month = dbtime->tm_mon + 1;
Sqlbuf->year = dbtime->tm_year + 1900; Sqlbuf->year = dbtime->tm_year + 1900;
Sqlbuf->fraction = 0;
} // endif Buf_Type } // endif Buf_Type
if (Nullable)
*StrLen = (Value->IsNull()) ? SQL_NULL_DATA :
(IsTypeNum(Buf_Type)) ? 0 : SQL_NTS;
} // end of WriteColumn
/* -------------------------- Class TDBXDBC -------------------------- */
/***********************************************************************/
/* Implementation of the TDBODBC class. */
/***********************************************************************/
PTDB TDBXDBC::CopyOne(PTABS t)
{
PTDB tp;
PXSRCCOL cp1, cp2;
PGLOBAL g = t->G; // Is this really useful ???
tp = new(g) TDBXDBC(this);
for (cp1 = (PXSRCCOL)Columns; cp1; cp1 = (PXSRCCOL)cp1->GetNext()) {
cp2 = new(g) XSRCCOL(cp1, tp); // Make a copy
NewPointer(t, cp1, cp2);
} // endfor cp1
return tp;
} // end of CopyOne
/***********************************************************************/
/* Allocate XSRC column description block. */
/***********************************************************************/
PCOL TDBXDBC::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
{
PXSRCCOL colp = new(g) XSRCCOL(cdp, this, cprec, n);
if (!colp->Flag)
Cmdcol = colp->GetName();
return colp;
} // end of MakeCol
/***********************************************************************/
/* MakeCMD: make the SQL statement to send to ODBC connection. */
/***********************************************************************/
char *TDBXDBC::MakeCMD(PGLOBAL g)
{
char *xcmd = NULL;
if (To_Filter) {
if (Cmdcol) {
char col[128], cmd[1024];
int n;
memset(cmd, 0, sizeof(cmd));
n = sscanf(To_Filter, "%s = '%1023c", col, cmd);
if (n == 2 && !stricmp(col, Cmdcol)) {
xcmd = (char*)PlugSubAlloc(g, NULL, strlen(cmd) + 1);
strcpy(xcmd, cmd);
xcmd[strlen(xcmd) - 1] = 0;
} else
strcpy(g->Message, "Invalid command specification filter");
} else
strcpy(g->Message, "No command column in select list");
} else if (!Srcdef)
strcpy(g->Message, "No Srcdef default command");
else
xcmd = Srcdef;
return xcmd;
} // end of MakeCMD
#if 0
/***********************************************************************/
/* ODBC Bind Parameter function. */
/***********************************************************************/
bool TDBXDBC::BindParameters(PGLOBAL g)
{
PODBCCOL colp;
for (colp = (PODBCCOL)Columns; colp; colp = (PODBCCOL)colp->Next) {
colp->AllocateBuffers(g, 0);
if (Ocp->BindParam(colp))
return true;
} // endfor colp
return false;
} // end of BindParameters
#endif // 0
/***********************************************************************/
/* XDBC GetMaxSize: returns table size (always one row). */
/***********************************************************************/
int TDBXDBC::GetMaxSize(PGLOBAL g)
{
if (MaxSize < 0)
MaxSize = 1;
return MaxSize;
} // end of GetMaxSize
/***********************************************************************/
/* ODBC Access Method opening routine. */
/* New method now that this routine is called recursively (last table */
/* first in reverse order): index blocks are immediately linked to */
/* join block of next table if it exists or else are discarted. */
/***********************************************************************/
bool TDBXDBC::OpenDB(PGLOBAL g)
{
bool rc = false;
if (g->Trace)
htrc("ODBC OpenDB: tdbp=%p tdb=R%d use=%dmode=%d\n",
this, Tdb_No, Use, Mode);
if (Use == USE_OPEN) {
strcpy(g->Message, "Multiple execution is not allowed");
return true;
} // endif use
/*********************************************************************/
/* Open an ODBC connection for this table. */
/* Note: this may not be the proper way to do. Perhaps it is better */
/* to test whether a connection is already open for this datasource */
/* and if so to allocate just a new result set. But this only for */
/* drivers allowing concurency in getting results ??? */
/*********************************************************************/
if (!Ocp)
Ocp = new(g) ODBConn(g, this);
else if (Ocp->IsOpen())
Ocp->Close();
if (Ocp->Open(Connect, Options) < 1)
return true;
Use = USE_OPEN; // Do it now in case we are recursively called
if (Mode != MODE_READ) {
strcpy(g->Message, "No INSERT/DELETE/UPDATE of XDBC tables");
return true;
} // endif Mode
/*********************************************************************/
/* Get the command to execute. */
/*********************************************************************/
if (!(Query = MakeCMD(g))) {
Ocp->Close();
return true;
} // endif Query
Rows = 1;
if (Ocp->PrepareSQL(Query)) {
strcpy(g->Message, "Parameters not supported");
AftRows = -1;
} else
AftRows = 0;
return false;
} // end of OpenDB
/***********************************************************************/
/* ReadDB: Data Base read routine for xdbc access method. */
/***********************************************************************/
int TDBXDBC::ReadDB(PGLOBAL g)
{
if (trace)
htrc("XDBC ReadDB: query=%s\n", SVP(Query));
if (Rows--) {
if (!AftRows)
AftRows = Ocp->ExecuteSQL(true);
} else
return RC_EF;
Fpos++; // Used for progress info
return RC_OK;
} // end of ReadDB
/***********************************************************************/
/* Data Base delete line routine for ODBC access method. */
/***********************************************************************/
int TDBXDBC::WriteDB(PGLOBAL g)
{
strcpy(g->Message, "Execsrc tables are read only");
return RC_FX;
} // end of DeleteDB
/* --------------------------- XSRCCOL ------------------------------- */
/***********************************************************************/
/* XSRCCOL public constructor. */
/***********************************************************************/
XSRCCOL::XSRCCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am)
: ODBCCOL(cdp, tdbp, cprec, i, am)
{
// Set additional ODBC access method information for column.
Flag = cdp->GetOffset();
} // end of XSRCCOL constructor
/***********************************************************************/
/* XSRCCOL constructor used for copying columns. */
/* tdbp is the pointer to the new table descriptor. */
/***********************************************************************/
XSRCCOL::XSRCCOL(XSRCCOL *col1, PTDB tdbp) : ODBCCOL(col1, tdbp)
{
Flag = col1->Flag;
} // end of XSRCCOL copy constructor
/***********************************************************************/
/* ReadColumn: set column value according to Flag. */
/***********************************************************************/
void XSRCCOL::ReadColumn(PGLOBAL g)
{
PTDBXDBC tdbp = (PTDBXDBC)To_Tdb;
switch (Flag) {
case 0: Value->SetValue_psz(tdbp->Query); break;
case 1: Value->SetValue(tdbp->AftRows); break;
case 2: Value->SetValue_psz(g->Message); break;
default: Value->SetValue_psz("Invalid Flag"); break;
} // endswitch Flag
} // end of ReadColumn
/***********************************************************************/
/* WriteColumn: Should never be called. */
/***********************************************************************/
void XSRCCOL::WriteColumn(PGLOBAL g)
{
// Should never be called
} // end of WriteColumn } // end of WriteColumn
/* ---------------------------TDBSRC class --------------------------- */ /* ---------------------------TDBSRC class --------------------------- */
......
/*************** Tabodbc H Declares Source Code File (.H) **************/ /*************** Tabodbc H Declares Source Code File (.H) **************/
/* Name: TABODBC.H Version 1.5 */ /* Name: TABODBC.H Version 1.6 */
/* */ /* */
/* (C) Copyright to the author Olivier BERTRAND 2000-2013 */ /* (C) Copyright to the author Olivier BERTRAND 2000-2013 */
/* */ /* */
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
typedef class ODBCDEF *PODEF; typedef class ODBCDEF *PODEF;
typedef class TDBODBC *PTDBODBC; typedef class TDBODBC *PTDBODBC;
typedef class ODBCCOL *PODBCCOL; typedef class ODBCCOL *PODBCCOL;
typedef class TDBXDBC *PTDBXDBC;
typedef class XSRCCOL *PXSRCCOL;
typedef class TDBOIF *PTDBOIF; typedef class TDBOIF *PTDBOIF;
typedef class OIFCOL *POIFCOL; typedef class OIFCOL *POIFCOL;
typedef class TDBSRC *PTDBSRC; typedef class TDBSRC *PTDBSRC;
...@@ -19,6 +21,8 @@ typedef class TDBSRC *PTDBSRC; ...@@ -19,6 +21,8 @@ typedef class TDBSRC *PTDBSRC;
/* ODBC table. */ /* ODBC table. */
/***********************************************************************/ /***********************************************************************/
class DllExport ODBCDEF : public TABDEF { /* Logical table description */ class DllExport ODBCDEF : public TABDEF { /* Logical table description */
friend class TDBODBC;
friend class TDBXDBC;
public: public:
// Constructor // Constructor
ODBCDEF(void); ODBCDEF(void);
...@@ -29,6 +33,7 @@ class DllExport ODBCDEF : public TABDEF { /* Logical table description */ ...@@ -29,6 +33,7 @@ class DllExport ODBCDEF : public TABDEF { /* Logical table description */
PSZ GetTabname(void) {return Tabname;} PSZ GetTabname(void) {return Tabname;}
PSZ GetTabowner(void) {return Tabowner;} PSZ GetTabowner(void) {return Tabowner;}
PSZ GetTabqual(void) {return Tabqual;} PSZ GetTabqual(void) {return Tabqual;}
PSZ GetSrcdef(void) {return Srcdef;}
PSZ GetQchar(void) {return (Qchar && *Qchar) ? Qchar : NULL;} PSZ GetQchar(void) {return (Qchar && *Qchar) ? Qchar : NULL;}
int GetCatver(void) {return Catver;} int GetCatver(void) {return Catver;}
int GetOptions(void) {return Options;} int GetOptions(void) {return Options;}
...@@ -43,9 +48,11 @@ class DllExport ODBCDEF : public TABDEF { /* Logical table description */ ...@@ -43,9 +48,11 @@ class DllExport ODBCDEF : public TABDEF { /* Logical table description */
PSZ Tabname; /* External table name */ PSZ Tabname; /* External table name */
PSZ Tabowner; /* External table owner */ PSZ Tabowner; /* External table owner */
PSZ Tabqual; /* External table qualifier */ PSZ Tabqual; /* External table qualifier */
PSZ Srcdef; /* The source table SQL definition */
PSZ Qchar; /* Identifier quoting character */ PSZ Qchar; /* Identifier quoting character */
int Catver; /* ODBC version for catalog functions */ int Catver; /* ODBC version for catalog functions */
int Options; /* Open connection options */ int Options; /* Open connection options */
bool Xsrc; /* Execution type */
}; // end of ODBCDEF }; // end of ODBCDEF
#if !defined(NODBC) #if !defined(NODBC)
...@@ -92,10 +99,10 @@ class TDBODBC : public TDBASE { ...@@ -92,10 +99,10 @@ class TDBODBC : public TDBASE {
int Decode(char *utf, char *buf, size_t n); int Decode(char *utf, char *buf, size_t n);
char *MakeSQL(PGLOBAL g, bool cnt); char *MakeSQL(PGLOBAL g, bool cnt);
//bool MakeUpdate(PGLOBAL g, PSELECT selist); //bool MakeUpdate(PGLOBAL g, PSELECT selist);
//bool MakeInsert(PGLOBAL g); bool MakeInsert(PGLOBAL g);
//bool MakeDelete(PGLOBAL g); //bool MakeDelete(PGLOBAL g);
//bool MakeFilter(PGLOBAL g, bool c); //bool MakeFilter(PGLOBAL g, bool c);
//bool BindParameters(PGLOBAL g); bool BindParameters(PGLOBAL g);
// Members // Members
ODBConn *Ocp; // Points to an ODBC connection class ODBConn *Ocp; // Points to an ODBC connection class
...@@ -104,6 +111,7 @@ class TDBODBC : public TDBASE { ...@@ -104,6 +111,7 @@ class TDBODBC : public TDBASE {
char *TableName; // Points to ODBC table name char *TableName; // Points to ODBC table name
char *Owner; // Points to ODBC table Owner char *Owner; // Points to ODBC table Owner
char *Qualifier; // Points to ODBC table Qualifier char *Qualifier; // Points to ODBC table Qualifier
char *Srcdef; // The source table SQL definition
char *Query; // Points to SQL statement char *Query; // Points to SQL statement
char *Count; // Points to count(*) SQL statement char *Count; // Points to count(*) SQL statement
//char *Where; // Points to local where clause //char *Where; // Points to local where clause
...@@ -122,7 +130,7 @@ class TDBODBC : public TDBASE { ...@@ -122,7 +130,7 @@ class TDBODBC : public TDBASE {
}; // end of class TDBODBC }; // end of class TDBODBC
/***********************************************************************/ /***********************************************************************/
/* Class ODBCCOL: DOS access method column descriptor. */ /* Class ODBCCOL: ODBC access method column descriptor. */
/* This A.M. is used for ODBC tables. */ /* This A.M. is used for ODBC tables. */
/***********************************************************************/ /***********************************************************************/
class ODBCCOL : public COLBLK { class ODBCCOL : public COLBLK {
...@@ -153,16 +161,85 @@ class ODBCCOL : public COLBLK { ...@@ -153,16 +161,85 @@ class ODBCCOL : public COLBLK {
ODBCCOL(void); ODBCCOL(void);
// Members // Members
TIMESTAMP_STRUCT *Sqlbuf; // To get SQL_TIMESTAMP's TIMESTAMP_STRUCT *Sqlbuf; // To get SQL_TIMESTAMP's
void *Bufp; // To extended buffer void *Bufp; // To extended buffer
PVBLK Blkp; // To Value Block PVBLK Blkp; // To Value Block
//char F_Date[12]; // Internal Date format //char F_Date[12]; // Internal Date format
PVAL To_Val; // To value used for Insert PVAL To_Val; // To value used for Insert
SQLLEN *StrLen; // As returned by ODBC SQLLEN *StrLen; // As returned by ODBC
SQLLEN Slen; // Used with Fetch SQLLEN Slen; // Used with Fetch
int Rank; // Rank (position) number in the query int Rank; // Rank (position) number in the query
}; // end of class ODBCCOL }; // end of class ODBCCOL
/***********************************************************************/
/* This is the ODBC Access Method class declaration that send */
/* commands to be executed by other DB ODBC drivers. */
/***********************************************************************/
class TDBXDBC : public TDBODBC {
friend class XSRCCOL;
friend class ODBConn;
public:
// Constructor
TDBXDBC(PODEF tdp = NULL) : TDBODBC(tdp) {Cmdcol = NULL;}
TDBXDBC(PTDBXDBC tdbp) : TDBODBC(tdbp) {Cmdcol = tdbp->Cmdcol;}
// Implementation
//virtual AMT GetAmType(void) {return TYPE_AM_ODBC;}
virtual PTDB Duplicate(PGLOBAL g)
{return (PTDB)new(g) TDBXDBC(this);}
// Methods
virtual PTDB CopyOne(PTABS t);
//virtual int GetRecpos(void);
//virtual PSZ GetFile(PGLOBAL g);
//virtual void SetFile(PGLOBAL g, PSZ fn);
//virtual void ResetSize(void);
//virtual int GetAffectedRows(void) {return AftRows;}
//virtual PSZ GetServer(void) {return "ODBC";}
// Database routines
virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
//virtual int GetProgMax(PGLOBAL g);
virtual int GetMaxSize(PGLOBAL g);
virtual bool OpenDB(PGLOBAL g);
virtual int ReadDB(PGLOBAL g);
virtual int WriteDB(PGLOBAL g);
//virtual int DeleteDB(PGLOBAL g, int irc);
//virtual void CloseDB(PGLOBAL g);
protected:
// Internal functions
char *MakeCMD(PGLOBAL g);
//bool BindParameters(PGLOBAL g);
// Members
char *Cmdcol; // The name of the Xsrc command column
}; // end of class TDBXDBC
/***********************************************************************/
/* Used by table in source execute mode. */
/***********************************************************************/
class XSRCCOL : public ODBCCOL {
friend class TDBXDBC;
public:
// Constructors
XSRCCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am = "ODBC");
XSRCCOL(XSRCCOL *colp, PTDB tdbp); // Constructor used in copy process
// Implementation
//virtual int GetAmType(void) {return TYPE_AM_ODBC;}
// Methods
virtual void ReadColumn(PGLOBAL g);
virtual void WriteColumn(PGLOBAL g);
// void Print(PGLOBAL g, FILE *, uint);
protected:
// Members
char *Buffer; // To get returned message
int Flag; // Column content desc
}; // end of class XSRCCOL
/***********************************************************************/ /***********************************************************************/
/* This is the class declaration for the Data Sources catalog table. */ /* This is the class declaration for the Data Sources catalog table. */
/***********************************************************************/ /***********************************************************************/
......
...@@ -591,6 +591,17 @@ bool PRXCOL::Init(PGLOBAL g) ...@@ -591,6 +591,17 @@ bool PRXCOL::Init(PGLOBAL g)
return FALSE; return FALSE;
} // end of Init } // end of Init
/***********************************************************************/
/* Reset the column descriptor to non evaluated yet. */
/***********************************************************************/
void PRXCOL::Reset(void)
{
if (Colp)
Colp->Reset();
Status &= ~BUF_READ;
} // end of Reset
/***********************************************************************/ /***********************************************************************/
/* ReadColumn: */ /* ReadColumn: */
/***********************************************************************/ /***********************************************************************/
...@@ -600,7 +611,7 @@ void PRXCOL::ReadColumn(PGLOBAL g) ...@@ -600,7 +611,7 @@ void PRXCOL::ReadColumn(PGLOBAL g)
htrc("PRX ReadColumn: name=%s\n", Name); htrc("PRX ReadColumn: name=%s\n", Name);
if (Colp) { if (Colp) {
Colp->ReadColumn(g); Colp->Eval(g);
Value->SetValue_pval(To_Val); Value->SetValue_pval(To_Val);
// Set null when applicable // Set null when applicable
......
...@@ -70,7 +70,7 @@ class DllExport TDBPRX : public TDBASE { ...@@ -70,7 +70,7 @@ class DllExport TDBPRX : public TDBASE {
virtual int GetRecpos(void) {return Tdbp->GetRecpos();} virtual int GetRecpos(void) {return Tdbp->GetRecpos();}
virtual void ResetDB(void) {Tdbp->ResetDB();} virtual void ResetDB(void) {Tdbp->ResetDB();}
virtual int RowNumber(PGLOBAL g, bool b = FALSE); virtual int RowNumber(PGLOBAL g, bool b = FALSE);
virtual PSZ GetServer(void) {return (Tdbp) ? Tdbp->GetServer() : (char*) "?";} virtual PSZ GetServer(void) {return (Tdbp) ? Tdbp->GetServer() : (PSZ)"?";}
// Database routines // Database routines
virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n); virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
...@@ -105,6 +105,7 @@ class DllExport PRXCOL : public COLBLK { ...@@ -105,6 +105,7 @@ class DllExport PRXCOL : public COLBLK {
virtual int GetAmType(void) {return TYPE_AM_PRX;} virtual int GetAmType(void) {return TYPE_AM_PRX;}
// Methods // Methods
virtual void Reset(void);
virtual bool IsSpecial(void) {return Pseudo;} virtual bool IsSpecial(void) {return Pseudo;}
virtual void ReadColumn(PGLOBAL g); virtual void ReadColumn(PGLOBAL g);
bool Init(PGLOBAL g); bool Init(PGLOBAL g);
......
...@@ -253,7 +253,7 @@ XCLCOL::XCLCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i) ...@@ -253,7 +253,7 @@ XCLCOL::XCLCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i)
void XCLCOL::ReadColumn(PGLOBAL g) void XCLCOL::ReadColumn(PGLOBAL g)
{ {
if (((PTDBXCL)To_Tdb)->New) { if (((PTDBXCL)To_Tdb)->New) {
Colp->ReadColumn(g); Colp->Eval(g);
strcpy(Cbuf, To_Val->GetCharValue()); strcpy(Cbuf, To_Val->GetCharValue());
Cp = Cbuf; Cp = Cbuf;
} // endif New } // endif New
...@@ -272,9 +272,11 @@ void XCLCOL::ReadColumn(PGLOBAL g) ...@@ -272,9 +272,11 @@ void XCLCOL::ReadColumn(PGLOBAL g)
} else if (Nullable) { } else if (Nullable) {
Value->Reset(); Value->Reset();
Value->SetNull(true); Value->SetNull(true);
} else } else {
// Skip that row // Skip that row
((PTDBXCL)To_Tdb)->RowFlag = 2; ((PTDBXCL)To_Tdb)->RowFlag = 2;
Colp->Reset();
} // endif Cp
if (Cp && *Cp) if (Cp && *Cp)
// More to come from the same row // More to come from the same row
......
...@@ -90,7 +90,7 @@ class XCLCOL : public PRXCOL { ...@@ -90,7 +90,7 @@ class XCLCOL : public PRXCOL {
XCLCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i); XCLCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i);
// Methods // Methods
virtual void Reset(void) {} // Evaluated only by TDBXCL virtual void Reset(void) {Colp->Reset();} // Evaluated only by TDBXCL
virtual void ReadColumn(PGLOBAL g); virtual void ReadColumn(PGLOBAL g);
protected: protected:
......
...@@ -78,7 +78,9 @@ XMLDEF::XMLDEF(void) ...@@ -78,7 +78,9 @@ XMLDEF::XMLDEF(void)
DefNs = NULL; DefNs = NULL;
Attrib = NULL; Attrib = NULL;
Hdattr = NULL; Hdattr = NULL;
Coltype = 1;
Limit = 0; Limit = 0;
Header = 0;
Xpand = false; Xpand = false;
Usedom = false; Usedom = false;
} // end of XMLDEF constructor } // end of XMLDEF constructor
...@@ -338,17 +340,14 @@ PCOL TDBXML::InsertSpecialColumn(PGLOBAL g, PCOL colp) ...@@ -338,17 +340,14 @@ PCOL TDBXML::InsertSpecialColumn(PGLOBAL g, PCOL colp)
/***********************************************************************/ /***********************************************************************/
/* LoadTableFile: Load and parse an XML file. */ /* LoadTableFile: Load and parse an XML file. */
/***********************************************************************/ /***********************************************************************/
int TDBXML::LoadTableFile(PGLOBAL g) int TDBXML::LoadTableFile(PGLOBAL g, char *filename)
{ {
char filename[_MAX_PATH];
int rc = RC_OK, type = (Usedom) ? TYPE_FB_XML : TYPE_FB_XML2; int rc = RC_OK, type = (Usedom) ? TYPE_FB_XML : TYPE_FB_XML2;
PFBLOCK fp = NULL; PFBLOCK fp = NULL;
PDBUSER dup = (PDBUSER)g->Activityp->Aptr; PDBUSER dup = (PDBUSER)g->Activityp->Aptr;
/*********************************************************************/ if (Docp)
/* We used the file name relative to recorded datapath. */ return rc; // Already done
/*********************************************************************/
PlugSetPath(filename, Xfile, GetPath());
if (trace) if (trace)
htrc("TDBXML: loading %s\n", filename); htrc("TDBXML: loading %s\n", filename);
...@@ -397,6 +396,7 @@ int TDBXML::LoadTableFile(PGLOBAL g) ...@@ -397,6 +396,7 @@ int TDBXML::LoadTableFile(PGLOBAL g)
} else } else
rc = (errno == ENOENT) ? RC_NF : RC_INFO; rc = (errno == ENOENT) ? RC_NF : RC_INFO;
// Cannot make a Xblock until document is made
return rc; return rc;
} // endif Docp } // endif Docp
...@@ -418,9 +418,8 @@ int TDBXML::LoadTableFile(PGLOBAL g) ...@@ -418,9 +418,8 @@ int TDBXML::LoadTableFile(PGLOBAL g)
/***********************************************************************/ /***********************************************************************/
bool TDBXML::Initialize(PGLOBAL g) bool TDBXML::Initialize(PGLOBAL g)
{ {
char tabpath[64]; int rc;
int rc; PXMLCOL colp;
PXMLCOL colp;
if (Void) if (Void)
return false; return false;
...@@ -440,8 +439,13 @@ bool TDBXML::Initialize(PGLOBAL g) ...@@ -440,8 +439,13 @@ bool TDBXML::Initialize(PGLOBAL g)
#else #else
if (!Root) { if (!Root) {
#endif #endif
char tabpath[64], filename[_MAX_PATH];
// We used the file name relative to recorded datapath
PlugSetPath(filename, Xfile, GetPath());
// Load or re-use the table file // Load or re-use the table file
rc = LoadTableFile(g); rc = LoadTableFile(g, filename);
if (rc == RC_OK) { if (rc == RC_OK) {
// Get root node // Get root node
...@@ -503,6 +507,9 @@ bool TDBXML::Initialize(PGLOBAL g) ...@@ -503,6 +507,9 @@ bool TDBXML::Initialize(PGLOBAL g)
goto error; goto error;
} // endif NewDoc } // endif NewDoc
// Now we can link the Xblock
To_Xb = Docp->LinkXblock(g, Mode, rc, filename);
// Add a CONNECT comment node // Add a CONNECT comment node
// sprintf(buf, MSG(CREATED_PLUGDB), version); // sprintf(buf, MSG(CREATED_PLUGDB), version);
sprintf(buf, " Created by CONNECT %s ", version); sprintf(buf, " Created by CONNECT %s ", version);
...@@ -893,12 +900,21 @@ int TDBXML::DeleteDB(PGLOBAL g, int irc) ...@@ -893,12 +900,21 @@ int TDBXML::DeleteDB(PGLOBAL g, int irc)
if ((RowNode = Nlist->GetItem(g, Irow, RowNode)) == NULL) { if ((RowNode = Nlist->GetItem(g, Irow, RowNode)) == NULL) {
sprintf(g->Message, MSG(MISSING_ROWNODE), Irow); sprintf(g->Message, MSG(MISSING_ROWNODE), Irow);
return RC_FX; return RC_FX;
} else } else {
TabNode->DeleteChild(g, RowNode); TabNode->DeleteChild(g, RowNode);
if (Nlist->DropItem(g, Irow))
return RC_FX;
} // endif RowNode
Changed = true; Changed = true;
} else if (irc != RC_EF) { } else if (irc != RC_EF) {
TabNode->DeleteChild(g, RowNode); TabNode->DeleteChild(g, RowNode);
if (Nlist->DropItem(g, Irow))
return RC_FX;
Changed = true; Changed = true;
} // endif's irc } // endif's irc
......
...@@ -6,8 +6,6 @@ ...@@ -6,8 +6,6 @@
/* */ /* */
/* This file contains the XML table classes declares. */ /* This file contains the XML table classes declares. */
/***********************************************************************/ /***********************************************************************/
#define TYPE_AM_XML (AMT)127
typedef class XMLDEF *PXMLDEF; typedef class XMLDEF *PXMLDEF;
typedef class TDBXML *PTDBXML; typedef class TDBXML *PTDBXML;
typedef class XMLCOL *PXMLCOL; typedef class XMLCOL *PXMLCOL;
...@@ -81,7 +79,7 @@ class DllExport TDBXML : public TDBASE { ...@@ -81,7 +79,7 @@ class DllExport TDBXML : public TDBASE {
virtual void ResetDB(void) {N = 0;} virtual void ResetDB(void) {N = 0;}
virtual void ResetSize(void) {MaxSize = -1;} virtual void ResetSize(void) {MaxSize = -1;}
virtual int RowNumber(PGLOBAL g, bool b = false); virtual int RowNumber(PGLOBAL g, bool b = false);
int LoadTableFile(PGLOBAL g); int LoadTableFile(PGLOBAL g, char *filename);
bool Initialize(PGLOBAL g); bool Initialize(PGLOBAL g);
bool SetTabNode(PGLOBAL g); bool SetTabNode(PGLOBAL g);
void SetNodeAttr(PGLOBAL g, char *attr, PXNODE node); void SetNodeAttr(PGLOBAL g, char *attr, PXNODE node);
......
...@@ -447,13 +447,12 @@ int TYPBLK<TYPE>::Find(PVAL vp) ...@@ -447,13 +447,12 @@ int TYPBLK<TYPE>::Find(PVAL vp)
template <class TYPE> template <class TYPE>
int TYPBLK<TYPE>::GetMaxLength(void) int TYPBLK<TYPE>::GetMaxLength(void)
{ {
char buf[12]; char buf[32];
int i, n; int i, n, m;
for (i = n = 0; i < Nval; i++) { for (i = n = 0; i < Nval; i++) {
sprintf(buf, Fmt, Typp[i]); m = sprintf(buf, Fmt, Typp[i]);
n = max(n, m);
n = max(n, (signed)strlen(buf));
} // endfor i } // endfor i
return n; return n;
......
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