Merge 10.0-connect -> 10.0
This commit is contained in:
commit
7dc48ae327
@ -5147,6 +5147,7 @@ char check_if_ignore_table(const char *table_name, char *table_type)
|
||||
if (!opt_no_data &&
|
||||
(!my_strcasecmp(&my_charset_latin1, table_type, "MRG_MyISAM") ||
|
||||
!strcmp(table_type,"MRG_ISAM") ||
|
||||
!strcmp(table_type,"CONNECT") ||
|
||||
!strcmp(table_type,"FEDERATED")))
|
||||
result= IGNORE_DATA;
|
||||
}
|
||||
|
@ -379,6 +379,7 @@ sub main {
|
||||
mtr_report("Logging: $0 ", join(" ", @ARGV));
|
||||
|
||||
$DEFAULT_SUITES.= ',' . join(',', qw(
|
||||
connect
|
||||
query_response_time
|
||||
sequence
|
||||
spider
|
||||
|
@ -1117,3 +1117,95 @@
|
||||
fun:_nss_dns_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)
|
||||
(To_Tdb) ? To_Tdb->GetCat() : NULL)))
|
||||
return true;
|
||||
|
||||
Status = BUF_READY;
|
||||
AddStatus(BUF_READY);
|
||||
Value->SetNullable(Nullable);
|
||||
|
||||
#ifdef DEBTRACE
|
||||
|
@ -592,6 +592,18 @@ PXNODE DOMNODELIST::GetItem(PGLOBAL g, int n, PXNODE np)
|
||||
|
||||
} // 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 propriété n'a pas de méthode 'set'
|
||||
return false;
|
||||
} // end of DeleteItem
|
||||
|
||||
/* ----------------------- class DOMATTR ------------------------ */
|
||||
|
||||
/******************************************************************/
|
||||
@ -618,8 +630,8 @@ bool DOMATTR::SetText(PGLOBAL g, char *txtp, int len)
|
||||
Len = len;
|
||||
} // endif len
|
||||
|
||||
if (!MultiByteToWideChar(CP_ACP, 0, txtp, strlen(txtp) + 1,
|
||||
Ws, Len + 1)) {
|
||||
if (!MultiByteToWideChar(CP_UTF8, 0, txtp, strlen(txtp) + 1,
|
||||
Ws, Len + 1)) {
|
||||
sprintf(g->Message, MSG(WS_CONV_ERR), txtp);
|
||||
return true;
|
||||
} // endif
|
||||
|
@ -104,8 +104,9 @@ class DOMNODELIST : public XMLNODELIST {
|
||||
friend class DOMNODE;
|
||||
public:
|
||||
// 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 bool DropItem(PGLOBAL g, int n);
|
||||
|
||||
protected:
|
||||
// Constructor
|
||||
|
@ -165,7 +165,7 @@ extern "C" char nmfile[];
|
||||
extern "C" char pdebug[];
|
||||
|
||||
extern "C" {
|
||||
char version[]= "Version 1.01.0007 July 26, 2013";
|
||||
char version[]= "Version 1.01.0008 August 18, 2013";
|
||||
|
||||
#if defined(XMSG)
|
||||
char msglang[]; // Default message language
|
||||
@ -1093,7 +1093,8 @@ PTDB ha_connect::GetTDB(PGLOBAL g)
|
||||
|
||||
if (!xp->CheckQuery(valid_query_id) && tdbp
|
||||
&& !stricmp(tdbp->GetName(), table_name)
|
||||
&& tdbp->GetMode() == xmod) {
|
||||
&& (tdbp->GetMode() == xmod
|
||||
|| tdbp->GetAmType() == TYPE_AM_XML)) {
|
||||
tp= tdbp;
|
||||
tp->SetMode(xmod);
|
||||
} else if ((tp= CntGetTDB(g, table_name, xmod, this)))
|
||||
@ -1132,13 +1133,14 @@ bool ha_connect::OpenTable(PGLOBAL g, bool del)
|
||||
break;
|
||||
} // 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)
|
||||
char *p;
|
||||
unsigned int k1, k2, n1, n2;
|
||||
Field* *field;
|
||||
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;
|
||||
|
||||
k1= k2= 0;
|
||||
@ -1373,7 +1375,8 @@ int ha_connect::ScanRecord(PGLOBAL g, uchar *buf)
|
||||
fp->option_struct->special)
|
||||
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)) {
|
||||
for (colp= tp->GetSetCols(); colp; colp= colp->GetNext())
|
||||
if (!stricmp(colp->GetName(), fp->field_name))
|
||||
@ -2658,8 +2661,9 @@ int ha_connect::delete_all_rows()
|
||||
PGLOBAL g= xp->g;
|
||||
DBUG_ENTER("ha_connect::delete_all_rows");
|
||||
|
||||
// Close and reopen the table so it will be deleted
|
||||
rc= CloseTable(g);
|
||||
if (tdbp && tdbp->GetAmType() != TYPE_AM_XML)
|
||||
// Close and reopen the table so it will be deleted
|
||||
rc= CloseTable(g);
|
||||
|
||||
if (!(OpenTable(g))) {
|
||||
if (CntDeleteRow(g, tdbp, true)) {
|
||||
@ -3462,7 +3466,7 @@ static bool add_field(String *sql, const char *field_name, int typ, int len,
|
||||
{
|
||||
bool error= false;
|
||||
const char *type= PLGtoMYSQLtype(typ, dbf);
|
||||
type= PLGtoMYSQLtype(typ, true);
|
||||
// type= PLGtoMYSQLtype(typ, true); ?????
|
||||
|
||||
error|= sql->append('`');
|
||||
error|= sql->append(field_name);
|
||||
@ -3612,6 +3616,7 @@ static int init_table_share(THD *thd,
|
||||
static int init_table_share(THD* thd,
|
||||
TABLE_SHARE *table_s,
|
||||
HA_CREATE_INFO *create_info,
|
||||
// char *dsn,
|
||||
String *sql)
|
||||
{
|
||||
bool oom= false;
|
||||
@ -3670,10 +3675,12 @@ static int init_table_share(THD* thd,
|
||||
} // endfor opt
|
||||
|
||||
if (create_info->connect_string.length) {
|
||||
//if (dsn) {
|
||||
oom|= sql->append(' ');
|
||||
oom|= sql->append("CONNECTION='");
|
||||
oom|= sql->append_for_single_quote(create_info->connect_string.str,
|
||||
create_info->connect_string.length);
|
||||
// oom|= sql->append_for_single_quote(dsn, strlen(dsn));
|
||||
oom|= sql->append('\'');
|
||||
|
||||
if (oom)
|
||||
@ -3715,6 +3722,25 @@ static void add_option(THD* thd, HA_CREATE_INFO *create_info,
|
||||
#endif // NEW_WAY
|
||||
} // end of add_option
|
||||
|
||||
// Used to check whether a MYSQL table is created on itself
|
||||
static bool CheckSelf(PGLOBAL g, TABLE_SHARE *s, const char *host,
|
||||
const char *db, char *tab, const char *src, int port)
|
||||
{
|
||||
if (src)
|
||||
return false;
|
||||
else if (host && stricmp(host, "localhost") && strcmp(host, "127.0.0.1"))
|
||||
return false;
|
||||
else if (db && stricmp(db, s->db.str))
|
||||
return false;
|
||||
else if (tab && stricmp(tab, s->table_name.str))
|
||||
return false;
|
||||
else if (port && port != (signed)GetDefaultPort())
|
||||
return false;
|
||||
|
||||
strcpy(g->Message, "This MySQL table is defined on itself");
|
||||
return true;
|
||||
} // end of CheckSelf
|
||||
|
||||
/**
|
||||
@brief
|
||||
connect_assisted_discovery() is called when creating a table with no columns.
|
||||
@ -3733,13 +3759,13 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
|
||||
{
|
||||
char spc= ',', qch= 0;
|
||||
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;
|
||||
char *tab, *dsn;
|
||||
#if defined(WIN32)
|
||||
char *nsp= NULL, *cls= NULL;
|
||||
#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);
|
||||
bool bif, ok= false, dbf= false;
|
||||
TABTYPE ttp= TAB_UNDEF;
|
||||
@ -3760,7 +3786,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
|
||||
if (!g)
|
||||
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
|
||||
ttp= GetTypeID(topt->type);
|
||||
@ -3778,23 +3804,23 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
|
||||
col= topt->colist;
|
||||
|
||||
if (topt->oplist) {
|
||||
host= GetListOption(g,"host", topt->oplist, "localhost");
|
||||
user= GetListOption(g,"user", topt->oplist, "root");
|
||||
host= GetListOption(g, "host", topt->oplist, "localhost");
|
||||
user= GetListOption(g, "user", topt->oplist, "root");
|
||||
// Default value db can come from the DBNAME=xxx option.
|
||||
db= GetListOption(g,"database", topt->oplist, db);
|
||||
col= GetListOption(g,"colist", topt->oplist, col);
|
||||
ocl= GetListOption(g,"occurcol", topt->oplist, NULL);
|
||||
pic= GetListOption(g,"pivotcol", topt->oplist, NULL);
|
||||
fcl= GetListOption(g,"fnccol", topt->oplist, NULL);
|
||||
rnk= GetListOption(g,"rankcol", topt->oplist, NULL);
|
||||
pwd= GetListOption(g,"password", topt->oplist);
|
||||
prt= GetListOption(g,"port", topt->oplist);
|
||||
port= (prt) ? atoi(prt) : 0;
|
||||
db= GetListOption(g, "database", topt->oplist, db);
|
||||
col= GetListOption(g, "colist", topt->oplist, col);
|
||||
ocl= GetListOption(g, "occurcol", topt->oplist, NULL);
|
||||
pic= GetListOption(g, "pivotcol", topt->oplist, NULL);
|
||||
fcl= GetListOption(g, "fnccol", topt->oplist, NULL);
|
||||
rnk= GetListOption(g, "rankcol", topt->oplist, NULL);
|
||||
pwd= GetListOption(g, "password", topt->oplist);
|
||||
#if defined(WIN32)
|
||||
nsp= GetListOption(g,"namespace", topt->oplist);
|
||||
cls= GetListOption(g,"class", topt->oplist);
|
||||
nsp= GetListOption(g, "namespace", topt->oplist);
|
||||
cls= GetListOption(g, "class", topt->oplist);
|
||||
#endif // WIN32
|
||||
port= atoi(GetListOption(g, "port", topt->oplist, "0"));
|
||||
mxr= atoi(GetListOption(g,"maxerr", topt->oplist, "0"));
|
||||
cop= atoi(GetListOption(g, "checkdsn", topt->oplist, "0"));
|
||||
} else {
|
||||
host= "localhost";
|
||||
user= "root";
|
||||
@ -3840,7 +3866,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
|
||||
} // endif p
|
||||
|
||||
} 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)
|
||||
add_option(thd, create_info, "tabname", tab);
|
||||
@ -3850,8 +3876,18 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
|
||||
switch (ttp) {
|
||||
#if defined(ODBC_SUPPORT)
|
||||
case TAB_ODBC:
|
||||
if (!(dsn= create_info->connect_string.str)
|
||||
&& !(fnc & (FNC_DSN | FNC_DRIVER)))
|
||||
dsn= create_info->connect_string.str;
|
||||
|
||||
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);
|
||||
else
|
||||
ok= true;
|
||||
@ -3873,31 +3909,46 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
|
||||
case TAB_MYSQL:
|
||||
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();
|
||||
PDBUSER dup= PlgGetUser(g);
|
||||
PCATLG cat= (dup) ? dup->Catalog : NULL;
|
||||
|
||||
dsn= (char*)PlugSubAlloc(g, NULL, strlen(dsn) + 1);
|
||||
strncpy(dsn, create_info->connect_string.str,
|
||||
create_info->connect_string.length);
|
||||
dsn[create_info->connect_string.length]= 0;
|
||||
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)) {
|
||||
host= mydef->GetHostname();
|
||||
user= mydef->GetUsername();
|
||||
pwd= mydef->GetPassword();
|
||||
db= mydef->GetDatabase();
|
||||
tab= mydef->GetTabname();
|
||||
port= mydef->GetPortnumber();
|
||||
if (!mydef->ParseURL(g, dsn, false)) {
|
||||
if (mydef->GetHostname())
|
||||
host= mydef->GetHostname();
|
||||
|
||||
if (mydef->GetUsername())
|
||||
user= mydef->GetUsername();
|
||||
|
||||
if (mydef->GetPassword())
|
||||
pwd= mydef->GetPassword();
|
||||
|
||||
if (mydef->GetDatabase())
|
||||
db= mydef->GetDatabase();
|
||||
|
||||
if (mydef->GetTabname())
|
||||
tab= mydef->GetTabname();
|
||||
|
||||
if (mydef->GetPortnumber())
|
||||
port= mydef->GetPortnumber();
|
||||
|
||||
} else
|
||||
ok= false;
|
||||
|
||||
} else if (!user)
|
||||
user= "root";
|
||||
|
||||
if (CheckSelf(g, table_s, host, db, tab, src, port))
|
||||
ok= false;
|
||||
|
||||
break;
|
||||
#endif // MYSQL_SUPPORT
|
||||
#if defined(WIN32)
|
||||
@ -3946,7 +3997,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
|
||||
else
|
||||
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);
|
||||
|
||||
if (qrp && ttp == TAB_OCCUR)
|
||||
@ -3964,7 +4015,12 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
|
||||
switch (fnc) {
|
||||
case FNC_NO:
|
||||
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;
|
||||
case FNC_TABLE:
|
||||
qrp= ODBCTables(g, dsn, (char *) tab, true);
|
||||
@ -4130,6 +4186,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
|
||||
#else // !NEW_WAY
|
||||
if (!rc)
|
||||
rc= init_table_share(thd, table_s, create_info, &sql);
|
||||
// rc= init_table_share(thd, table_s, create_info, dsn, &sql);
|
||||
#endif // !NEW_WAY
|
||||
|
||||
return rc;
|
||||
@ -4250,6 +4307,54 @@ int ha_connect::create(const char *name, TABLE *table_arg,
|
||||
DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
|
||||
} // endif tabname
|
||||
|
||||
case TAB_MYSQL:
|
||||
{const char *src= options->srcdef;
|
||||
char *host, *db, *tab= (char*)options->tabname;
|
||||
int port;
|
||||
|
||||
host= GetListOption(g, "host", options->oplist, NULL);
|
||||
db= GetListOption(g, "database", options->oplist, NULL);
|
||||
port= atoi(GetListOption(g, "port", options->oplist, "0"));
|
||||
|
||||
if (create_info->connect_string.str) {
|
||||
char *dsn;
|
||||
int len= create_info->connect_string.length;
|
||||
PMYDEF mydef= new(g) MYSQLDEF();
|
||||
PDBUSER dup= PlgGetUser(g);
|
||||
PCATLG cat= (dup) ? dup->Catalog : NULL;
|
||||
|
||||
dsn= (char*)PlugSubAlloc(g, NULL, len + 1);
|
||||
strncpy(dsn, create_info->connect_string.str, len);
|
||||
dsn[len]= 0;
|
||||
mydef->SetName(create_info->alias);
|
||||
mydef->SetCat(cat);
|
||||
|
||||
if (!mydef->ParseURL(g, dsn, false)) {
|
||||
if (mydef->GetHostname())
|
||||
host= mydef->GetHostname();
|
||||
|
||||
if (mydef->GetDatabase())
|
||||
db= mydef->GetDatabase();
|
||||
|
||||
if (mydef->GetTabname())
|
||||
tab= mydef->GetTabname();
|
||||
|
||||
if (mydef->GetPortnumber())
|
||||
port= mydef->GetPortnumber();
|
||||
|
||||
} else {
|
||||
my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
|
||||
DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
|
||||
} // endif ParseURL
|
||||
|
||||
} // endif connect_string
|
||||
|
||||
if (CheckSelf(g, table_arg->s, host, db, tab, src, port)) {
|
||||
my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
|
||||
DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
|
||||
} // endif CheckSelf
|
||||
|
||||
}break;
|
||||
default: /* do nothing */;
|
||||
break;
|
||||
} // endswitch ttp
|
||||
|
@ -208,7 +208,8 @@ public:
|
||||
return (HA_NO_TRANSACTIONS | HA_REC_NOT_IN_SEQ | HA_HAS_RECORDS |
|
||||
HA_NO_AUTO_INCREMENT | HA_NO_PREFIX_CHAR_KEYS |
|
||||
HA_NO_COPY_ON_ALTER | HA_CAN_VIRTUAL_COLUMNS |
|
||||
/*HA_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
|
||||
|
@ -14,6 +14,10 @@
|
||||
#include "my_global.h"
|
||||
//#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)
|
||||
#error "XPath not supported"
|
||||
#endif
|
||||
@ -47,8 +51,6 @@ typedef struct _x2block { /* Loaded XML file block */
|
||||
short Type; /* TYPE_FB_XML */
|
||||
int Retcode; /* Return code from Load */
|
||||
xmlDocPtr Docp; /* Document interface pointer */
|
||||
// xmlXPathContextPtr Ctxp;
|
||||
// xmlXPathObjectPtr Xop;
|
||||
} X2BLOCK, *PX2BLOCK;
|
||||
|
||||
/******************************************************************/
|
||||
@ -91,6 +93,8 @@ class LIBXMLDOC : public XMLDOCUMENT {
|
||||
xmlNodeSetPtr Nlist;
|
||||
xmlXPathContextPtr Ctxp;
|
||||
xmlXPathObjectPtr Xop;
|
||||
xmlXPathObjectPtr NlXop;
|
||||
xmlErrorPtr Xerr;
|
||||
char *Buf; // Temporary
|
||||
bool Nofreelist;
|
||||
}; // end of class LIBXMLDOC
|
||||
@ -141,6 +145,7 @@ class XML2NODELIST : public XMLNODELIST {
|
||||
// Methods
|
||||
virtual int GetLength(void);
|
||||
virtual PXNODE GetItem(PGLOBAL g, int n, PXNODE np);
|
||||
virtual bool DropItem(PGLOBAL g, int n);
|
||||
|
||||
protected:
|
||||
// Constructor
|
||||
@ -180,6 +185,23 @@ extern int trace;
|
||||
} // "C"
|
||||
|
||||
#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 xmlMallocFunc Malloc;
|
||||
static xmlMallocFunc MallocA;
|
||||
@ -188,42 +210,53 @@ static xmlStrdupFunc Strdup;
|
||||
|
||||
void xmlMyFree(void *mem)
|
||||
{
|
||||
if (trace)
|
||||
htrc("Freeing at %p\n", mem);
|
||||
if (trace) {
|
||||
htrc("%.4d Freeing at %p %s\n", ++m, mem, s);
|
||||
*s = 0;
|
||||
} // endif trace
|
||||
Free(mem);
|
||||
} // end of xmlMyFree
|
||||
|
||||
void *xmlMyMalloc(size_t size)
|
||||
{
|
||||
void *p = Malloc(size);
|
||||
if (trace)
|
||||
htrc("Allocating %.5d at %p\n", size, p);
|
||||
if (trace) {
|
||||
htrc("%.4d Allocating %.5d at %p %s\n", ++m, size, p, s);
|
||||
*s = 0;
|
||||
} // endif trace
|
||||
return p;
|
||||
} // end of xmlMyMalloc
|
||||
|
||||
void *xmlMyMallocAtomic(size_t size)
|
||||
{
|
||||
void *p = MallocA(size);
|
||||
if (trace)
|
||||
htrc("Atom alloc %.5d at %p\n", size, p);
|
||||
if (trace) {
|
||||
htrc("%.4d Atom alloc %.5d at %p %s\n", ++m, size, p, s);
|
||||
*s = 0;
|
||||
} // endif trace
|
||||
return p;
|
||||
} // end of xmlMyMallocAtomic
|
||||
|
||||
void *xmlMyRealloc(void *mem, size_t size)
|
||||
{
|
||||
void *p = Realloc(mem, size);
|
||||
if (trace)
|
||||
htrc("ReAlloc %.5d to %p from %p\n", size, p, mem);
|
||||
if (trace) {
|
||||
htrc("%.4d ReAlloc %.5d to %p from %p %s\n", ++m, size, p, mem, s);
|
||||
*s = 0;
|
||||
} // endif trace
|
||||
return p;
|
||||
} // end of xmlMyRealloc
|
||||
|
||||
char *xmlMyStrdup(const char *str)
|
||||
{
|
||||
char *p = Strdup(str);
|
||||
if (trace)
|
||||
htrc("Duplicating to %p from %p %s\n", p, str, str);
|
||||
if (trace) {
|
||||
htrc("%.4d Duplicating to %p from %p %s %s\n", ++m, p, str, str, s);
|
||||
*s = 0;
|
||||
} // endif trace
|
||||
return p;
|
||||
} // end of xmlMyStrdup
|
||||
#define htrc xtrc
|
||||
#endif // MEMORY_TRACE
|
||||
|
||||
/******************************************************************/
|
||||
@ -295,6 +328,8 @@ LIBXMLDOC::LIBXMLDOC(char *nsl, char *nsdf, char *enc, PFBLOCK fp)
|
||||
Nlist = NULL;
|
||||
Ctxp = NULL;
|
||||
Xop = NULL;
|
||||
NlXop = NULL;
|
||||
Xerr = NULL;
|
||||
Buf = NULL;
|
||||
Nofreelist = false;
|
||||
} // end of LIBXMLDOC constructor
|
||||
@ -321,9 +356,10 @@ bool LIBXMLDOC::ParseFile(char *fn)
|
||||
Encoding = (char*)Docp->encoding;
|
||||
|
||||
return false;
|
||||
} else
|
||||
return true;
|
||||
} else if ((Xerr = xmlGetLastError()))
|
||||
xmlResetError(Xerr);
|
||||
|
||||
return true;
|
||||
} // end of ParseFile
|
||||
|
||||
/******************************************************************/
|
||||
@ -344,8 +380,6 @@ PFBLOCK LIBXMLDOC::LinkXblock(PGLOBAL g, MODE m, int rc, char *fn)
|
||||
xp->Length = (m == MODE_READ) ? 1 : 0;
|
||||
xp->Retcode = rc;
|
||||
xp->Docp = Docp;
|
||||
// xp->Ctxp = Ctxp;
|
||||
// xp->Xop = Xop;
|
||||
|
||||
// Return xp as a fp
|
||||
return (PFBLOCK)xp;
|
||||
@ -356,6 +390,9 @@ PFBLOCK LIBXMLDOC::LinkXblock(PGLOBAL g, MODE m, int rc, char *fn)
|
||||
/******************************************************************/
|
||||
bool LIBXMLDOC::NewDoc(PGLOBAL g, char *ver)
|
||||
{
|
||||
if (trace)
|
||||
htrc("NewDoc\n");
|
||||
|
||||
return ((Docp = xmlNewDoc(BAD_CAST ver)) == NULL);
|
||||
} // end of NewDoc
|
||||
|
||||
@ -462,8 +499,7 @@ int LIBXMLDOC::DumpDoc(PGLOBAL g, char *ofn)
|
||||
if (xmlSaveFormatFileEnc((const char *)ofn, Docp, Encoding, 0) < 0) {
|
||||
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;
|
||||
} // endif Save
|
||||
// rc = xmlDocDump(of, Docp);
|
||||
@ -497,17 +533,44 @@ void LIBXMLDOC::CloseDoc(PGLOBAL g, PFBLOCK xp)
|
||||
if (trace)
|
||||
htrc("CloseDoc: xp=%p count=%d\n", xp, (xp) ? xp->Count : 0);
|
||||
|
||||
if (xp && xp->Count == 1) {
|
||||
if (Nlist)
|
||||
//if (xp && xp->Count == 1) {
|
||||
if (Nlist) {
|
||||
xmlXPathFreeNodeSet(Nlist);
|
||||
|
||||
if (Xop)
|
||||
if ((Xerr = xmlGetLastError()))
|
||||
xmlResetError(Xerr);
|
||||
|
||||
Nlist = NULL;
|
||||
} // endif Nlist
|
||||
|
||||
if (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);
|
||||
|
||||
} // endif Count
|
||||
if ((Xerr = xmlGetLastError()))
|
||||
xmlResetError(Xerr);
|
||||
|
||||
Ctxp = NULL;
|
||||
} // endif Ctxp
|
||||
|
||||
// } // endif Count
|
||||
|
||||
CloseXML2File(g, xp, false);
|
||||
} // end of Close
|
||||
@ -560,18 +623,29 @@ xmlNodeSetPtr LIBXMLDOC::GetNodeList(PGLOBAL g, xmlNodePtr np, char *xp)
|
||||
|
||||
} // endfor nsp
|
||||
|
||||
} else {
|
||||
} // endif Ctxp
|
||||
|
||||
if (Xop) {
|
||||
if (trace)
|
||||
htrc("Calling xmlXPathFreeNodeSetList Xop=%p\n", Xop);
|
||||
htrc("Calling xmlXPathFreeNodeSetList Xop=%p NOFREE=%d\n",
|
||||
Xop, Nofreelist);
|
||||
|
||||
if (Nofreelist) {
|
||||
// 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;
|
||||
} else
|
||||
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
|
||||
Ctxp->node = np;
|
||||
@ -990,6 +1064,8 @@ void XML2NODE::AddText(PGLOBAL g, char *txtp)
|
||||
/******************************************************************/
|
||||
void XML2NODE::DeleteChild(PGLOBAL g, PXNODE dnp)
|
||||
{
|
||||
xmlErrorPtr xerr;
|
||||
|
||||
if (trace)
|
||||
htrc("DeleteChild: node=%p\n", dnp);
|
||||
|
||||
@ -999,12 +1075,39 @@ void XML2NODE::DeleteChild(PGLOBAL g, PXNODE dnp)
|
||||
// This is specific to row nodes
|
||||
if (text && text->type == XML_TEXT_NODE) {
|
||||
xmlUnlinkNode(text);
|
||||
|
||||
if ((xerr = xmlGetLastError()))
|
||||
goto err;
|
||||
|
||||
xmlFreeNode(text);
|
||||
|
||||
if ((xerr = xmlGetLastError()))
|
||||
goto err;
|
||||
|
||||
} // endif type
|
||||
|
||||
xmlUnlinkNode(np);
|
||||
|
||||
if ((xerr = xmlGetLastError()))
|
||||
goto err;
|
||||
|
||||
xmlFreeNode(np);
|
||||
|
||||
if ((xerr = xmlGetLastError()))
|
||||
goto err;
|
||||
|
||||
Delete(dnp);
|
||||
|
||||
if ((xerr = xmlGetLastError()))
|
||||
goto err;
|
||||
|
||||
return;
|
||||
|
||||
err:
|
||||
if (trace)
|
||||
htrc("DeleteChild: errmsg=%s\n", xerr->message);
|
||||
|
||||
xmlResetError(xerr);
|
||||
} // end of DeleteChild
|
||||
|
||||
/* -------------------- class XML2NODELIST ---------------------- */
|
||||
@ -1045,6 +1148,22 @@ PXNODE XML2NODELIST::GetItem(PGLOBAL g, int n, PXNODE np)
|
||||
|
||||
} // 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 ------------------------ */
|
||||
|
||||
/******************************************************************/
|
||||
|
@ -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};
|
||||
char *fld, *fmt, cmd[128];
|
||||
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;
|
||||
PCOLRES crp;
|
||||
MYSQLC myc;
|
||||
@ -166,7 +166,7 @@ PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db,
|
||||
// Get type, type name, and precision
|
||||
fld = myc.GetCharField(1);
|
||||
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) {
|
||||
sprintf(g->Message, MSG(BAD_FIELD_TYPE), fld);
|
||||
|
@ -54,6 +54,7 @@ uint GetDefaultPort(void);
|
||||
class DllItem MYSQLC {
|
||||
friend class TDBMYSQL;
|
||||
friend class MYSQLCOL;
|
||||
friend class TDBMYEXC;
|
||||
// Construction
|
||||
public:
|
||||
MYSQLC(void);
|
||||
|
@ -217,3 +217,24 @@ t2 CREATE TABLE `t2` (
|
||||
SELECT * FROM t2;
|
||||
a
|
||||
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;
|
||||
SET @a=LOAD_FILE('MYSQLD_DATADIR/test/t1.xml');
|
||||
SELECT CAST(@a AS CHAR CHARACTER SET latin1);
|
||||
CAST(@a AS CHAR CHARACTER SET latin1) <?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Created by CONNECT Version 1.01.0007 July 26, 2013 -->
|
||||
<!-- Created by CONNECT Version 1.01.0008 August 18, 2013 -->
|
||||
<t1>
|
||||
<line>
|
||||
<node>ÀÁÂÃ</node>
|
||||
|
@ -10,7 +10,7 @@ let $PORT= `select @@port`;
|
||||
--disable_query_log
|
||||
--replace_result $PORT PORT
|
||||
--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
|
||||
WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1'
|
||||
AND ENGINE='CONNECT'
|
||||
@ -420,3 +420,17 @@ DROP TABLE t2, t1;
|
||||
# TODO: add test for YEAR
|
||||
# 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;
|
||||
|
@ -1,78 +1,78 @@
|
||||
-- source include/not_embedded.inc
|
||||
|
||||
let $PORT= `select @@port`;
|
||||
|
||||
--disable_query_log
|
||||
--replace_result $PORT PORT
|
||||
--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'
|
||||
if (!`SELECT count(*) FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1'
|
||||
AND ENGINE='CONNECT'
|
||||
AND CREATE_OPTIONS LIKE '%`table_type`=MySQL%'`)
|
||||
{
|
||||
Skip Need MySQL support;
|
||||
}
|
||||
DROP TABLE t1;
|
||||
--enable_query_log
|
||||
|
||||
--echo #
|
||||
--echo # Testing FILE privilege
|
||||
--echo #
|
||||
GRANT ALL PRIVILEGES ON *.* TO user@localhost;
|
||||
REVOKE FILE ON *.* FROM user@localhost;
|
||||
--connect(user,localhost,user,,)
|
||||
--connection user
|
||||
SELECT user();
|
||||
--replace_result $PORT PORT
|
||||
--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'
|
||||
--connection default
|
||||
SELECT user();
|
||||
CREATE TABLE t1remote (a INT NOT NULL);
|
||||
INSERT INTO t1remote VALUES (10),(20),(30);
|
||||
--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'
|
||||
SELECT * FROM t1;
|
||||
--connection user
|
||||
SELECT user();
|
||||
--error ER_ACCESS_DENIED_ERROR
|
||||
SELECT * FROM t1;
|
||||
--error ER_ACCESS_DENIED_ERROR
|
||||
INSERT INTO t1 VALUES ('xxx');
|
||||
--error ER_ACCESS_DENIED_ERROR
|
||||
DELETE FROM t1 WHERE a='xxx';
|
||||
--error ER_ACCESS_DENIED_ERROR
|
||||
UPDATE t1 SET a='yyy' WHERE a='xxx';
|
||||
--error ER_ACCESS_DENIED_ERROR
|
||||
TRUNCATE TABLE t1;
|
||||
--error ER_ACCESS_DENIED_ERROR
|
||||
ALTER TABLE t1 READONLY=1;
|
||||
--error ER_ACCESS_DENIED_ERROR
|
||||
CREATE VIEW v1 AS SELECT * FROM t1;
|
||||
|
||||
--echo # Testing a VIEW created with FILE privileges but accessed with no FILE
|
||||
--connection default
|
||||
SELECT user();
|
||||
CREATE VIEW v1 AS SELECT * FROM t1;
|
||||
--connection user
|
||||
SELECT user();
|
||||
--error ER_ACCESS_DENIED_ERROR
|
||||
SELECT * FROM v1;
|
||||
--error ER_ACCESS_DENIED_ERROR
|
||||
INSERT INTO v1 VALUES (2);
|
||||
--error ER_ACCESS_DENIED_ERROR
|
||||
UPDATE v1 SET a=123;
|
||||
--error ER_ACCESS_DENIED_ERROR
|
||||
DELETE FROM v1;
|
||||
|
||||
--disconnect user
|
||||
--connection default
|
||||
SELECT user();
|
||||
DROP VIEW v1;
|
||||
DROP TABLE t1, t1remote;
|
||||
DROP USER user@localhost;
|
||||
--echo #
|
||||
--echo # Testing FILE privileges done
|
||||
--echo #
|
||||
|
||||
-- source include/not_embedded.inc
|
||||
|
||||
let $PORT= `select @@port`;
|
||||
|
||||
--disable_query_log
|
||||
--replace_result $PORT PORT
|
||||
--error 0,ER_UNKNOWN_ERROR
|
||||
--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
|
||||
WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1'
|
||||
AND ENGINE='CONNECT'
|
||||
AND CREATE_OPTIONS LIKE '%`table_type`=MySQL%'`)
|
||||
{
|
||||
Skip Need MySQL support;
|
||||
}
|
||||
DROP TABLE t1;
|
||||
--enable_query_log
|
||||
|
||||
--echo #
|
||||
--echo # Testing FILE privilege
|
||||
--echo #
|
||||
GRANT ALL PRIVILEGES ON *.* TO user@localhost;
|
||||
REVOKE FILE ON *.* FROM user@localhost;
|
||||
--connect(user,localhost,user,,)
|
||||
--connection user
|
||||
SELECT user();
|
||||
--replace_result $PORT PORT
|
||||
--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'
|
||||
--connection default
|
||||
SELECT user();
|
||||
CREATE TABLE t1remote (a INT NOT NULL);
|
||||
INSERT INTO t1remote VALUES (10),(20),(30);
|
||||
--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'
|
||||
SELECT * FROM t1;
|
||||
--connection user
|
||||
SELECT user();
|
||||
--error ER_ACCESS_DENIED_ERROR
|
||||
SELECT * FROM t1;
|
||||
--error ER_ACCESS_DENIED_ERROR
|
||||
INSERT INTO t1 VALUES ('xxx');
|
||||
--error ER_ACCESS_DENIED_ERROR
|
||||
DELETE FROM t1 WHERE a='xxx';
|
||||
--error ER_ACCESS_DENIED_ERROR
|
||||
UPDATE t1 SET a='yyy' WHERE a='xxx';
|
||||
--error ER_ACCESS_DENIED_ERROR
|
||||
TRUNCATE TABLE t1;
|
||||
--error ER_ACCESS_DENIED_ERROR
|
||||
ALTER TABLE t1 READONLY=1;
|
||||
--error ER_ACCESS_DENIED_ERROR
|
||||
CREATE VIEW v1 AS SELECT * FROM t1;
|
||||
|
||||
--echo # Testing a VIEW created with FILE privileges but accessed with no FILE
|
||||
--connection default
|
||||
SELECT user();
|
||||
CREATE VIEW v1 AS SELECT * FROM t1;
|
||||
--connection user
|
||||
SELECT user();
|
||||
--error ER_ACCESS_DENIED_ERROR
|
||||
SELECT * FROM v1;
|
||||
--error ER_ACCESS_DENIED_ERROR
|
||||
INSERT INTO v1 VALUES (2);
|
||||
--error ER_ACCESS_DENIED_ERROR
|
||||
UPDATE v1 SET a=123;
|
||||
--error ER_ACCESS_DENIED_ERROR
|
||||
DELETE FROM v1;
|
||||
|
||||
--disconnect user
|
||||
--connection default
|
||||
SELECT user();
|
||||
DROP VIEW v1;
|
||||
DROP TABLE t1, t1remote;
|
||||
DROP USER user@localhost;
|
||||
--echo #
|
||||
--echo # Testing FILE privileges done
|
||||
--echo #
|
||||
|
||||
|
@ -1,8 +1,10 @@
|
||||
/***********************************************************************/
|
||||
/* ODBC catalog function prototypes. */
|
||||
/***********************************************************************/
|
||||
char *ODBCCheckConnection(PGLOBAL g, char *dsn, int cop);
|
||||
PQRYRES ODBCDataSources(PGLOBAL g, bool info);
|
||||
PQRYRES ODBCColumns(PGLOBAL g, char *dsn, char *table,
|
||||
char *colpat, bool info);
|
||||
PQRYRES ODBCSrcCols(PGLOBAL g, char *dsn, char *src);
|
||||
PQRYRES ODBCTables(PGLOBAL g, char *dsn, char *tabpat, bool info);
|
||||
PQRYRES ODBCDrivers(PGLOBAL g, bool info);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/************ 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 */
|
||||
/* */
|
||||
@ -13,6 +13,7 @@
|
||||
#if defined(WIN32)
|
||||
//nclude <io.h>
|
||||
//nclude <fcntl.h>
|
||||
#include <direct.h> // for getcwd
|
||||
#if defined(__BORLANDC__)
|
||||
#define __MFC_COMPAT__ // To define min/max as macro
|
||||
#endif
|
||||
@ -76,8 +77,9 @@ static short GetSQLType(int type)
|
||||
case TYPE_SHORT: tp = SQL_SMALLINT; break;
|
||||
case TYPE_INT: tp = SQL_INTEGER; 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_TINY : tp = SQL_TINYINT; break;
|
||||
} // endswitch type
|
||||
|
||||
return tp;
|
||||
@ -97,6 +99,7 @@ static int GetSQLCType(int type)
|
||||
case TYPE_DATE: tp = SQL_C_TIMESTAMP; break;
|
||||
case TYPE_BIGINT: tp = SQL_C_SBIGINT; break;
|
||||
case TYPE_FLOAT: tp = SQL_C_DOUBLE; break;
|
||||
case TYPE_TINY : tp = SQL_C_TINYINT; break;
|
||||
} // endswitch type
|
||||
|
||||
return tp;
|
||||
@ -127,9 +130,11 @@ int TranslateSQLType(int stp, int prec, int& len)
|
||||
type = TYPE_INT;
|
||||
break;
|
||||
case SQL_SMALLINT: // 5
|
||||
type = TYPE_SHORT;
|
||||
break;
|
||||
case SQL_TINYINT: // (-6)
|
||||
case SQL_BIT: // (-7)
|
||||
type = TYPE_SHORT;
|
||||
type = TYPE_TINY;
|
||||
break;
|
||||
case SQL_FLOAT: // 6
|
||||
case SQL_REAL: // 7
|
||||
@ -168,10 +173,36 @@ int TranslateSQLType(int stp, int prec, int& len)
|
||||
} // end of TranslateSQLType
|
||||
|
||||
/***********************************************************************/
|
||||
/* ODBConn static members initialization. */
|
||||
/* ODBCCheckConnection: Check completeness of connection string. */
|
||||
/***********************************************************************/
|
||||
//HENV ODBConn::m_henv = SQL_NULL_HENV;
|
||||
//int ODBConn::m_nAlloc = 0; // per-Appl reference to HENV above
|
||||
char *ODBCCheckConnection(PGLOBAL g, char *dsn, int cop)
|
||||
{
|
||||
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. */
|
||||
@ -225,7 +256,6 @@ static void ResetNullValues(CATPARM *cap)
|
||||
/***********************************************************************/
|
||||
/* ODBCColumns: constructs the result blocks containing all columns */
|
||||
/* of an ODBC table that will be retrieved by GetData commands. */
|
||||
/* Note: The first two columns (Qualifier, Owner) are ignored. */
|
||||
/***********************************************************************/
|
||||
PQRYRES ODBCColumns(PGLOBAL g, char *dsn, char *table,
|
||||
char *colpat, bool info)
|
||||
@ -251,7 +281,7 @@ PQRYRES ODBCColumns(PGLOBAL g, char *dsn, char *table,
|
||||
if (!info) {
|
||||
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;
|
||||
|
||||
// We fix a MySQL limit because some data sources return 32767
|
||||
@ -314,6 +344,17 @@ PQRYRES ODBCColumns(PGLOBAL g, char *dsn, char *table,
|
||||
return qrp;
|
||||
} // 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
|
||||
/**************************************************************************/
|
||||
/* MyODBCCols: returns column info as required by ha_connect::pre_create. */
|
||||
@ -800,6 +841,17 @@ void DBX::BuildErrorMessage(ODBConn* pdb, HSTMT hstmt)
|
||||
|
||||
} // 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. */
|
||||
/***********************************************************************/
|
||||
@ -818,7 +870,7 @@ ODBConn::ODBConn(PGLOBAL g, TDBODBC *tdbp)
|
||||
m_Catver = (tdbp) ? tdbp->Catver : 0;
|
||||
m_Connect = NULL;
|
||||
m_Updatable = true;
|
||||
//m_Transactions = false;
|
||||
m_Transact = false;
|
||||
m_IDQuoteChar = '\'';
|
||||
//*m_ErrMsg = '\0';
|
||||
} // end of ODBConn
|
||||
@ -1061,7 +1113,7 @@ bool ODBConn::Connect(DWORD Options)
|
||||
if (hWnd == NULL)
|
||||
hWnd = GetDesktopWindow();
|
||||
#else // !WIN32
|
||||
HWND hWnd = NULL;
|
||||
HWND hWnd = 1;
|
||||
#endif // !WIN32
|
||||
PGLOBAL& g = m_G;
|
||||
PDBUSER dup = PlgGetUser(g);
|
||||
@ -1204,8 +1256,7 @@ int ODBConn::ExecDirectSQL(char *sql, ODBCCOL *tocols)
|
||||
void *buffer;
|
||||
bool b;
|
||||
UWORD n;
|
||||
SWORD ncol, len, tp;
|
||||
SQLLEN afrw;
|
||||
SWORD len, tp, ncol = 0;
|
||||
ODBCCOL *colp;
|
||||
RETCODE rc;
|
||||
HSTMT hstmt;
|
||||
@ -1240,26 +1291,44 @@ int ODBConn::ExecDirectSQL(char *sql, ODBCCOL *tocols)
|
||||
if (trace)
|
||||
htrc("ExecDirect hstmt=%p %.64s\n", hstmt, sql);
|
||||
|
||||
do {
|
||||
rc = SQLExecDirect(hstmt, (PUCHAR)sql, 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 (ncol == 0) {
|
||||
// Update or Delete statement
|
||||
rc = SQLRowCount(hstmt, &afrw);
|
||||
if (m_Tdb->Srcdef) {
|
||||
// Be sure this is a query returning a result set
|
||||
do {
|
||||
rc = SQLPrepare(hstmt, (PUCHAR)sql, SQL_NTS);
|
||||
} while (rc == SQL_STILL_EXECUTING);
|
||||
|
||||
if (!Check(rc))
|
||||
ThrowDBX(rc, "SQLRowCount", hstmt);
|
||||
ThrowDBX(rc, "SQLPrepare", hstmt);
|
||||
|
||||
return afrw;
|
||||
} // endif ncol
|
||||
if (!Check(rc = SQLNumResultCols(hstmt, &ncol)))
|
||||
ThrowDBX(rc, "SQLNumResultCols", hstmt);
|
||||
|
||||
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 (!Check(rc))
|
||||
ThrowDBX(rc, "SQLExecute", hstmt);
|
||||
|
||||
} else {
|
||||
do {
|
||||
rc = SQLExecDirect(hstmt, (PUCHAR)sql, SQL_NTS);
|
||||
} while (rc == SQL_STILL_EXECUTING);
|
||||
|
||||
if (!Check(rc))
|
||||
ThrowDBX(rc, "SQLExecDirect", hstmt);
|
||||
|
||||
do {
|
||||
rc = SQLNumResultCols(hstmt, &ncol);
|
||||
} while (rc == SQL_STILL_EXECUTING);
|
||||
|
||||
} // endif Srcdef
|
||||
|
||||
for (n = 0, colp = tocols; colp; colp = (PODBCCOL)colp->GetNext())
|
||||
if (!colp->IsSpecial())
|
||||
@ -1407,10 +1476,33 @@ int ODBConn::PrepareSQL(char *sql)
|
||||
{
|
||||
PGLOBAL& g = m_G;
|
||||
bool b;
|
||||
UINT txn = 0;
|
||||
SWORD nparm;
|
||||
RETCODE rc;
|
||||
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 {
|
||||
b = false;
|
||||
|
||||
@ -1450,13 +1542,19 @@ int ODBConn::PrepareSQL(char *sql)
|
||||
for (int i = 0; i < MAX_NUM_OF_MSG && x->m_ErrMsg[i]; i++)
|
||||
htrc(x->m_ErrMsg[i]);
|
||||
|
||||
strcpy(m_G->Message, x->GetErrorMessage(0));
|
||||
strcpy(g->Message, x->GetErrorMessage(0));
|
||||
|
||||
if (b)
|
||||
SQLCancel(hstmt);
|
||||
|
||||
rc = SQLFreeStmt(hstmt, SQL_DROP);
|
||||
m_hstmt = NULL;
|
||||
|
||||
if (m_Transact) {
|
||||
rc = SQLEndTran(SQL_HANDLE_DBC, m_hdbc, SQL_ROLLBACK);
|
||||
m_Transact = false;
|
||||
} // endif m_Transact
|
||||
|
||||
return -1;
|
||||
} // end try/catch
|
||||
|
||||
@ -1465,27 +1563,59 @@ int ODBConn::PrepareSQL(char *sql)
|
||||
} // 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 {
|
||||
rc = SQLExecute(m_hstmt);
|
||||
do {
|
||||
rc = SQLExecute(m_hstmt);
|
||||
} while (rc == SQL_STILL_EXECUTING);
|
||||
|
||||
if (!Check(rc))
|
||||
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) {
|
||||
strcpy(m_G->Message, x->GetErrorMessage(0));
|
||||
SQLCancel(m_hstmt);
|
||||
rc = SQLFreeStmt(m_hstmt, SQL_DROP);
|
||||
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
|
||||
|
||||
return false;
|
||||
return (int)afrw;
|
||||
} // end of ExecuteSQL
|
||||
|
||||
/***********************************************************************/
|
||||
@ -1537,6 +1667,132 @@ bool ODBConn::BindParam(ODBCCOL *colp)
|
||||
return false;
|
||||
} // 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. */
|
||||
/***********************************************************************/
|
||||
@ -1840,6 +2096,11 @@ void ODBConn::Close()
|
||||
} // endif m_hstmt
|
||||
|
||||
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);
|
||||
|
||||
if (trace && rc != SQL_SUCCESS)
|
||||
|
@ -91,8 +91,7 @@ class DBX : public BLOCK {
|
||||
// Implementation (use ThrowDBX to create)
|
||||
RETCODE GetRC(void) {return m_RC;}
|
||||
PSZ GetMsg(void) {return m_Msg;}
|
||||
const char *GetErrorMessage(int i)
|
||||
{return (i >=0 && i < MAX_NUM_OF_MSG) ? m_ErrMsg[i] : "No ODBC error";}
|
||||
const char *GetErrorMessage(int i);
|
||||
|
||||
protected:
|
||||
void BuildErrorMessage(ODBConn* pdb, HSTMT hstmt = SQL_NULL_HSTMT);
|
||||
@ -107,6 +106,7 @@ class DBX : public BLOCK {
|
||||
/* ODBConn class. */
|
||||
/***********************************************************************/
|
||||
class ODBConn : public BLOCK {
|
||||
friend class TDBODBC;
|
||||
friend class DBX;
|
||||
friend PQRYRES GetColumnInfo(PGLOBAL, char*&, char *, int, PVBLK&);
|
||||
private:
|
||||
@ -142,11 +142,12 @@ class ODBConn : public BLOCK {
|
||||
int ExecDirectSQL(char *sql, ODBCCOL *tocols);
|
||||
int Fetch(void);
|
||||
int PrepareSQL(char *sql);
|
||||
bool ExecuteSQL(void);
|
||||
int ExecuteSQL(bool x);
|
||||
bool BindParam(ODBCCOL *colp);
|
||||
int GetCatInfo(CATPARM *cap);
|
||||
bool GetDataSources(PQRYRES qrp);
|
||||
bool GetDrivers(PQRYRES qrp);
|
||||
PQRYRES GetMetaData(PGLOBAL g, char *dsn, char *src);
|
||||
|
||||
public:
|
||||
// Set special options
|
||||
@ -185,5 +186,6 @@ class ODBConn : public BLOCK {
|
||||
int m_Catver;
|
||||
PSZ m_Connect;
|
||||
bool m_Updatable;
|
||||
bool m_Transact;
|
||||
char m_IDQuoteChar;
|
||||
}; // end of ODBConn class definition
|
||||
|
@ -1,7 +1,7 @@
|
||||
#ifndef _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;
|
||||
#define lseek64(fd, offset, whence) lseek((fd), (offset), (whence))
|
||||
#define open64(path, flags, mode) open((path), (flags), (mode))
|
||||
|
@ -111,6 +111,7 @@ enum AMT {TYPE_AM_ERROR = 0, /* Type not defined */
|
||||
TYPE_AM_PIVOT = 120, /* PIVOT access method type no */
|
||||
TYPE_AM_SRC = 121, /* PIVOT multiple column type no */
|
||||
TYPE_AM_FNC = 122, /* PIVOT source column type no */
|
||||
TYPE_AM_XML = 127, /* XML access method type no */
|
||||
TYPE_AM_XTB = 130, /* SYS table access method type */
|
||||
TYPE_AM_MAC = 137, /* MAC 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);
|
||||
int global_open(GLOBAL *g, int msgid, const char *filename, int flags);
|
||||
int global_open(GLOBAL *g, int msgid, const char *filename, int flags, int mode);
|
||||
DllExport LPCSTR PlugSetPath(LPSTR to, LPCSTR name, LPCSTR dir);
|
||||
char *MakeEscape(PGLOBAL g, char* str, char q);
|
||||
|
||||
bool PushWarning(PGLOBAL, PTDBASE);
|
||||
|
@ -731,6 +731,34 @@ bool EvalLikePattern(LPCSTR sp, LPCSTR tp)
|
||||
return (b);
|
||||
} /* 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. */
|
||||
/***********************************************************************/
|
||||
|
@ -147,6 +147,7 @@ class XMLNODELIST : public BLOCK {
|
||||
// Properties
|
||||
virtual int GetLength(void) = 0;
|
||||
virtual PXNODE GetItem(PGLOBAL, int, PXNODE = NULL) = 0;
|
||||
virtual bool DropItem(PGLOBAL, int) = 0;
|
||||
|
||||
protected:
|
||||
// Constructor
|
||||
|
@ -93,7 +93,7 @@ PQRYRES CSVColumns(PGLOBAL g, const char *fn, char sep, char q,
|
||||
PCOLRES crp;
|
||||
|
||||
if (info) {
|
||||
imax = 0;
|
||||
imax = hmax = 0;
|
||||
length[0] = 128;
|
||||
goto skipit;
|
||||
} // endif info
|
||||
|
@ -884,9 +884,11 @@ void TDBDIR::CloseDB(PGLOBAL g)
|
||||
_findclose(Hsearch);
|
||||
Hsearch = -1;
|
||||
#else // !WIN32
|
||||
// Close the DIR handle.
|
||||
closedir(Dir);
|
||||
Dir = NULL;
|
||||
// Close the DIR handle
|
||||
if (Dir) {
|
||||
closedir(Dir);
|
||||
Dir = NULL;
|
||||
} // endif dir
|
||||
#endif // !WIN32
|
||||
iFile = 0;
|
||||
} // end of CloseDB
|
||||
|
@ -86,6 +86,7 @@ MYSQLDEF::MYSQLDEF(void)
|
||||
Isview = FALSE;
|
||||
Bind = FALSE;
|
||||
Delayed = FALSE;
|
||||
Xsrc = FALSE;
|
||||
} // end of MYSQLDEF constructor
|
||||
|
||||
/***********************************************************************/
|
||||
@ -171,7 +172,7 @@ bool MYSQLDEF::GetServerInfo(PGLOBAL g, const char *server_name)
|
||||
/* true error */
|
||||
/* */
|
||||
/***********************************************************************/
|
||||
bool MYSQLDEF::ParseURL(PGLOBAL g, char *url)
|
||||
bool MYSQLDEF::ParseURL(PGLOBAL g, char *url, bool b)
|
||||
{
|
||||
if ((!strstr(url, "://") && (!strchr(url, '@')))) {
|
||||
// No :// or @ in connection string. Must be a straight
|
||||
@ -248,34 +249,41 @@ bool MYSQLDEF::ParseURL(PGLOBAL g, char *url)
|
||||
if ((Database = strchr(Hostname, '/'))) {
|
||||
*Database++ = 0;
|
||||
|
||||
if ((Tabname = strchr(Database, '/')))
|
||||
if ((Tabname = strchr(Database, '/'))) {
|
||||
*Tabname++ = 0;
|
||||
|
||||
// Make sure there's not an extra /
|
||||
if ((strchr(Tabname, '/'))) {
|
||||
strcpy(g->Message, "Syntax error in URL");
|
||||
return true;
|
||||
} // endif /
|
||||
// Make sure there's not an extra /
|
||||
if ((strchr(Tabname, '/'))) {
|
||||
strcpy(g->Message, "Syntax error in URL");
|
||||
return true;
|
||||
} // endif /
|
||||
|
||||
} // endif Tabname
|
||||
|
||||
} // endif database
|
||||
|
||||
if ((sport = strchr(Hostname, ':')))
|
||||
*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)
|
||||
Username = Cat->GetStringCatInfo(g, "User", "*");
|
||||
Username = (b) ? Cat->GetStringCatInfo(g, "User", "*") : NULL;
|
||||
|
||||
if (Hostname[0] == 0)
|
||||
Hostname = Cat->GetStringCatInfo(g, "Host", "localhost");
|
||||
Hostname = (b) ? Cat->GetStringCatInfo(g, "Host", "localhost") : NULL;
|
||||
|
||||
if (!Database || !*Database)
|
||||
Database = Cat->GetStringCatInfo(g, "Database", "*");
|
||||
Database = (b) ? Cat->GetStringCatInfo(g, "Database", "*") : NULL;
|
||||
|
||||
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
|
||||
|
||||
#if 0
|
||||
@ -347,6 +355,7 @@ bool MYSQLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
|
||||
if ((Srcdef = Cat->GetStringCatInfo(g, "Srcdef", NULL)))
|
||||
Isview = TRUE;
|
||||
|
||||
Xsrc = Cat->GetBoolCatInfo("Execsrc", FALSE);
|
||||
return FALSE;
|
||||
} // end of DefineAM
|
||||
|
||||
@ -355,7 +364,9 @@ bool MYSQLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
|
||||
/***********************************************************************/
|
||||
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);
|
||||
else
|
||||
return new(g) TDBMYSQL(this);
|
||||
@ -507,6 +518,9 @@ bool TDBMYSQL::MakeSelect(PGLOBAL g)
|
||||
if (To_Filter)
|
||||
strcat(strcat(Query, " WHERE "), To_Filter);
|
||||
|
||||
if (trace)
|
||||
htrc("Query=%s\n", Query);
|
||||
|
||||
// Now we know how much to suballocate
|
||||
PlugSubAlloc(g, NULL, strlen(Query) + 1);
|
||||
return FALSE;
|
||||
@ -1040,18 +1054,20 @@ int TDBMYSQL::DeleteDB(PGLOBAL g, int irc)
|
||||
/***********************************************************************/
|
||||
void TDBMYSQL::CloseDB(PGLOBAL g)
|
||||
{
|
||||
if (Mode == MODE_INSERT) {
|
||||
char cmd[64];
|
||||
int w;
|
||||
PDBUSER dup = PlgGetUser(g);
|
||||
if (Myc.Connected()) {
|
||||
if (Mode == MODE_INSERT) {
|
||||
char cmd[64];
|
||||
int w;
|
||||
PDBUSER dup = PlgGetUser(g);
|
||||
|
||||
dup->Step = "Enabling indexes";
|
||||
sprintf(cmd, "ALTER TABLE `%s` ENABLE KEYS", Tabname);
|
||||
Myc.m_Rows = -1; // To execute the query
|
||||
m_Rc = Myc.ExecSQL(g, cmd, &w);
|
||||
} // endif m_Rc
|
||||
dup->Step = "Enabling indexes";
|
||||
sprintf(cmd, "ALTER TABLE `%s` ENABLE KEYS", Tabname);
|
||||
Myc.m_Rows = -1; // To execute the query
|
||||
m_Rc = Myc.ExecSQL(g, cmd, &w);
|
||||
} // endif m_Rc
|
||||
|
||||
Myc.Close();
|
||||
Myc.Close();
|
||||
} // endif Myc
|
||||
|
||||
if (trace)
|
||||
htrc("MySQL CloseDB: closing %s rc=%d\n", Name, m_Rc);
|
||||
@ -1275,6 +1291,212 @@ void MYSQLCOL::WriteColumn(PGLOBAL g)
|
||||
|
||||
} // 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 --------------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
|
@ -3,8 +3,10 @@
|
||||
|
||||
typedef class MYSQLDEF *PMYDEF;
|
||||
typedef class TDBMYSQL *PTDBMY;
|
||||
typedef class MYSQLC *PMYC;
|
||||
typedef class MYSQLCOL *PMYCOL;
|
||||
typedef class TDBMYEXC *PTDBMYX;
|
||||
typedef class MYXCOL *PMYXCOL;
|
||||
typedef class MYSQLC *PMYC;
|
||||
|
||||
/* ------------------------- MYSQL classes --------------------------- */
|
||||
|
||||
@ -38,7 +40,7 @@ class MYSQLDEF : public TABDEF {/* Logical table description */
|
||||
// Methods
|
||||
virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
|
||||
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);
|
||||
|
||||
protected:
|
||||
@ -54,6 +56,7 @@ class MYSQLDEF : public TABDEF {/* Logical table description */
|
||||
bool Isview; /* TRUE if this table is a MySQL view */
|
||||
bool Bind; /* Use prepared statement on insert */
|
||||
bool Delayed; /* Delayed insert */
|
||||
bool Xsrc; /* Execution type */
|
||||
}; // end of MYSQLDEF
|
||||
|
||||
/***********************************************************************/
|
||||
@ -158,6 +161,87 @@ class MYSQLCOL : public COLBLK {
|
||||
int Rank; // Rank (position) number in the query
|
||||
}; // 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. */
|
||||
/***********************************************************************/
|
||||
|
@ -1,7 +1,7 @@
|
||||
/************* Tabodbc C++ Program Source Code File (.CPP) *************/
|
||||
/* PROGRAM NAME: TABODBC */
|
||||
/* ------------- */
|
||||
/* Version 2.5 */
|
||||
/* Version 2.6 */
|
||||
/* */
|
||||
/* COPYRIGHT: */
|
||||
/* ---------- */
|
||||
@ -90,8 +90,9 @@ extern int num_read, num_there, num_eq[2]; // Statistics
|
||||
/***********************************************************************/
|
||||
ODBCDEF::ODBCDEF(void)
|
||||
{
|
||||
Connect = Tabname = Tabowner = Tabqual = Qchar = NULL;
|
||||
Catver = Options = 0;
|
||||
Connect = Tabname = Tabowner = Tabqual = Srcdef = Qchar = NULL;
|
||||
Catver = Options = 0;
|
||||
Xsrc = false;
|
||||
} // end of ODBCDEF constructor
|
||||
|
||||
/***********************************************************************/
|
||||
@ -99,17 +100,17 @@ ODBCDEF::ODBCDEF(void)
|
||||
/***********************************************************************/
|
||||
bool ODBCDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
|
||||
{
|
||||
int dop = ODBConn::noOdbcDialog; // Default for options
|
||||
|
||||
Desc = Connect = Cat->GetStringCatInfo(g, "Connect", "");
|
||||
Tabname = Cat->GetStringCatInfo(g, "Name",
|
||||
(Catfunc & (FNC_TABLE | FNC_COL)) ? NULL : Name);
|
||||
Tabname = Cat->GetStringCatInfo(g, "Tabname", Tabname);
|
||||
Tabowner = Cat->GetStringCatInfo(g, "Owner", "");
|
||||
Tabqual = Cat->GetStringCatInfo(g, "Qualifier", "");
|
||||
Srcdef = Cat->GetStringCatInfo(g, "Srcdef", NULL);
|
||||
Qchar = Cat->GetStringCatInfo(g, "Qchar", "");
|
||||
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
|
||||
return false;
|
||||
} // end of DefineAM
|
||||
@ -125,7 +126,9 @@ PTDB ODBCDEF::GetTable(PGLOBAL g, MODE m)
|
||||
/* Allocate a TDB of the proper type. */
|
||||
/* Column blocks will be allocated only when needed. */
|
||||
/*********************************************************************/
|
||||
switch (Catfunc) {
|
||||
if (Xsrc)
|
||||
tdbp = new(g) TDBXDBC(this);
|
||||
else switch (Catfunc) {
|
||||
case FNC_COL:
|
||||
tdbp = new(g) TDBOCL(this);
|
||||
break;
|
||||
@ -161,19 +164,21 @@ TDBODBC::TDBODBC(PODEF tdp) : TDBASE(tdp)
|
||||
Cnp = NULL;
|
||||
|
||||
if (tdp) {
|
||||
Connect = tdp->GetConnect();
|
||||
TableName = tdp->GetTabname();
|
||||
Owner = tdp->GetTabowner();
|
||||
Qualifier = tdp->GetTabqual();
|
||||
Connect = tdp->Connect;
|
||||
TableName = tdp->Tabname;
|
||||
Owner = tdp->Tabowner;
|
||||
Qualifier = tdp->Tabqual;
|
||||
Srcdef = tdp->Srcdef;
|
||||
Quote = tdp->GetQchar();
|
||||
Options = tdp->GetOptions();
|
||||
Options = tdp->Options;
|
||||
Rows = tdp->GetElemt();
|
||||
Catver = tdp->GetCatver();
|
||||
Catver = tdp->Catver;
|
||||
} else {
|
||||
Connect = NULL;
|
||||
TableName = NULL;
|
||||
Owner = NULL;
|
||||
Qualifier = NULL;
|
||||
Srcdef = NULL;
|
||||
Quote = NULL;
|
||||
Options = 0;
|
||||
Rows = 0;
|
||||
@ -201,6 +206,7 @@ TDBODBC::TDBODBC(PTDBODBC tdbp) : TDBASE(tdbp)
|
||||
TableName = tdbp->TableName;
|
||||
Owner = tdbp->Owner;
|
||||
Qualifier = tdbp->Qualifier;
|
||||
Srcdef = tdbp->Srcdef;
|
||||
Quote = tdbp->Quote;
|
||||
Query = tdbp->Query;
|
||||
Count = tdbp->Count;
|
||||
@ -299,7 +305,6 @@ void TDBODBC::SetFile(PGLOBAL g, PSZ fn)
|
||||
DBQ = fn;
|
||||
} // end of SetFile
|
||||
|
||||
|
||||
/******************************************************************/
|
||||
/* Convert an UTF-8 string to latin characters. */
|
||||
/******************************************************************/
|
||||
@ -314,7 +319,6 @@ int TDBODBC::Decode(char *txt, char *buf, size_t n)
|
||||
return 0;
|
||||
} // end of Decode
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
/* MakeSQL: make the SQL statement use with ODBC connection. */
|
||||
/* Note: when implementing EOM filtering, column only used in local */
|
||||
@ -329,6 +333,9 @@ char *TDBODBC::MakeSQL(PGLOBAL g, bool cnt)
|
||||
PTABLE tablep = To_Table;
|
||||
PCOL colp;
|
||||
|
||||
if (Srcdef)
|
||||
return Srcdef;
|
||||
|
||||
if (!cnt) {
|
||||
// Normal SQL statement to retrieve results
|
||||
for (colp = Columns; colp; colp = colp->GetNext())
|
||||
@ -430,6 +437,83 @@ char *TDBODBC::MakeSQL(PGLOBAL g, bool cnt)
|
||||
return sql;
|
||||
} // 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. */
|
||||
/***********************************************************************/
|
||||
@ -448,6 +532,16 @@ void TDBODBC::ResetSize(void)
|
||||
int TDBODBC::GetMaxSize(PGLOBAL g)
|
||||
{
|
||||
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)
|
||||
Ocp = new(g) ODBConn(g, this);
|
||||
|
||||
@ -466,19 +560,18 @@ int TDBODBC::GetMaxSize(PGLOBAL g)
|
||||
|
||||
if ((MaxSize = Ocp->GetResultSize(Count, Cnp)) < 0)
|
||||
return -3;
|
||||
|
||||
#endif // 0
|
||||
} // endif MaxSize
|
||||
|
||||
return MaxSize;
|
||||
} // 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)
|
||||
{
|
||||
return (Mode == MODE_DELETE || Mode == MODE_UPDATE) ? 0
|
||||
: GetMaxSize(g);
|
||||
return GetMaxSize(g);
|
||||
} // end of GetProgMax
|
||||
|
||||
/***********************************************************************/
|
||||
@ -546,14 +639,24 @@ bool TDBODBC::OpenDB(PGLOBAL g)
|
||||
if (!colp->IsSpecial())
|
||||
colp->AllocateBuffers(g, Rows);
|
||||
|
||||
} else
|
||||
rc = true;
|
||||
} else {
|
||||
Ocp->Close();
|
||||
return true;
|
||||
} // endif Query
|
||||
|
||||
if (!rc)
|
||||
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 {
|
||||
strcpy(g->Message, "ODBC tables are read only in this version");
|
||||
strcpy(g->Message, "No DELETE/UPDATE of ODBC tablesd");
|
||||
return true;
|
||||
} // endelse
|
||||
|
||||
@ -592,30 +695,6 @@ int TDBODBC::ReadDB(PGLOBAL g)
|
||||
// Direct access of ODBC tables is not implemented yet
|
||||
strcpy(g->Message, MSG(NO_ODBC_DIRECT));
|
||||
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
|
||||
|
||||
/*********************************************************************/
|
||||
@ -641,8 +720,15 @@ int TDBODBC::ReadDB(PGLOBAL g)
|
||||
/***********************************************************************/
|
||||
int TDBODBC::WriteDB(PGLOBAL g)
|
||||
{
|
||||
strcpy(g->Message, "ODBC tables are read only");
|
||||
return RC_FX;
|
||||
int n = Ocp->ExecuteSQL(false);
|
||||
|
||||
if (n < 0) {
|
||||
AftRows = n;
|
||||
return RC_FX;
|
||||
} else
|
||||
AftRows += n;
|
||||
|
||||
return RC_OK;
|
||||
} // end of WriteDB
|
||||
|
||||
/***********************************************************************/
|
||||
@ -664,7 +750,8 @@ void TDBODBC::CloseDB(PGLOBAL g)
|
||||
// To_Kindex = NULL;
|
||||
// } // endif
|
||||
|
||||
Ocp->Close();
|
||||
if (Ocp)
|
||||
Ocp->Close();
|
||||
|
||||
if (trace)
|
||||
htrc("ODBC CloseDB: closing %s\n", Name);
|
||||
@ -892,7 +979,7 @@ void ODBCCOL::WriteColumn(PGLOBAL g)
|
||||
/* Do convert the column value if necessary. */
|
||||
/*********************************************************************/
|
||||
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) {
|
||||
struct tm tm, *dbtime = ((DTVAL*)Value)->GetGmTime(&tm);
|
||||
@ -903,8 +990,245 @@ void ODBCCOL::WriteColumn(PGLOBAL g)
|
||||
Sqlbuf->day = dbtime->tm_mday;
|
||||
Sqlbuf->month = dbtime->tm_mon + 1;
|
||||
Sqlbuf->year = dbtime->tm_year + 1900;
|
||||
Sqlbuf->fraction = 0;
|
||||
} // 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
|
||||
|
||||
/* ---------------------------TDBSRC class --------------------------- */
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*************** 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 */
|
||||
/* */
|
||||
@ -11,6 +11,8 @@
|
||||
typedef class ODBCDEF *PODEF;
|
||||
typedef class TDBODBC *PTDBODBC;
|
||||
typedef class ODBCCOL *PODBCCOL;
|
||||
typedef class TDBXDBC *PTDBXDBC;
|
||||
typedef class XSRCCOL *PXSRCCOL;
|
||||
typedef class TDBOIF *PTDBOIF;
|
||||
typedef class OIFCOL *POIFCOL;
|
||||
typedef class TDBSRC *PTDBSRC;
|
||||
@ -19,6 +21,8 @@ typedef class TDBSRC *PTDBSRC;
|
||||
/* ODBC table. */
|
||||
/***********************************************************************/
|
||||
class DllExport ODBCDEF : public TABDEF { /* Logical table description */
|
||||
friend class TDBODBC;
|
||||
friend class TDBXDBC;
|
||||
public:
|
||||
// Constructor
|
||||
ODBCDEF(void);
|
||||
@ -29,6 +33,7 @@ class DllExport ODBCDEF : public TABDEF { /* Logical table description */
|
||||
PSZ GetTabname(void) {return Tabname;}
|
||||
PSZ GetTabowner(void) {return Tabowner;}
|
||||
PSZ GetTabqual(void) {return Tabqual;}
|
||||
PSZ GetSrcdef(void) {return Srcdef;}
|
||||
PSZ GetQchar(void) {return (Qchar && *Qchar) ? Qchar : NULL;}
|
||||
int GetCatver(void) {return Catver;}
|
||||
int GetOptions(void) {return Options;}
|
||||
@ -43,9 +48,11 @@ class DllExport ODBCDEF : public TABDEF { /* Logical table description */
|
||||
PSZ Tabname; /* External table name */
|
||||
PSZ Tabowner; /* External table owner */
|
||||
PSZ Tabqual; /* External table qualifier */
|
||||
PSZ Srcdef; /* The source table SQL definition */
|
||||
PSZ Qchar; /* Identifier quoting character */
|
||||
int Catver; /* ODBC version for catalog functions */
|
||||
int Options; /* Open connection options */
|
||||
bool Xsrc; /* Execution type */
|
||||
}; // end of ODBCDEF
|
||||
|
||||
#if !defined(NODBC)
|
||||
@ -92,10 +99,10 @@ class TDBODBC : public TDBASE {
|
||||
int Decode(char *utf, char *buf, size_t n);
|
||||
char *MakeSQL(PGLOBAL g, bool cnt);
|
||||
//bool MakeUpdate(PGLOBAL g, PSELECT selist);
|
||||
//bool MakeInsert(PGLOBAL g);
|
||||
bool MakeInsert(PGLOBAL g);
|
||||
//bool MakeDelete(PGLOBAL g);
|
||||
//bool MakeFilter(PGLOBAL g, bool c);
|
||||
//bool BindParameters(PGLOBAL g);
|
||||
bool BindParameters(PGLOBAL g);
|
||||
|
||||
// Members
|
||||
ODBConn *Ocp; // Points to an ODBC connection class
|
||||
@ -104,6 +111,7 @@ class TDBODBC : public TDBASE {
|
||||
char *TableName; // Points to ODBC table name
|
||||
char *Owner; // Points to ODBC table Owner
|
||||
char *Qualifier; // Points to ODBC table Qualifier
|
||||
char *Srcdef; // The source table SQL definition
|
||||
char *Query; // Points to SQL statement
|
||||
char *Count; // Points to count(*) SQL statement
|
||||
//char *Where; // Points to local where clause
|
||||
@ -122,7 +130,7 @@ class TDBODBC : public TDBASE {
|
||||
}; // 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. */
|
||||
/***********************************************************************/
|
||||
class ODBCCOL : public COLBLK {
|
||||
@ -153,16 +161,85 @@ class ODBCCOL : public COLBLK {
|
||||
ODBCCOL(void);
|
||||
|
||||
// Members
|
||||
TIMESTAMP_STRUCT *Sqlbuf; // To get SQL_TIMESTAMP's
|
||||
void *Bufp; // To extended buffer
|
||||
TIMESTAMP_STRUCT *Sqlbuf; // To get SQL_TIMESTAMP's
|
||||
void *Bufp; // To extended buffer
|
||||
PVBLK Blkp; // To Value Block
|
||||
//char F_Date[12]; // Internal Date format
|
||||
PVAL To_Val; // To value used for Insert
|
||||
SQLLEN *StrLen; // As returned by ODBC
|
||||
SQLLEN Slen; // Used with Fetch
|
||||
int Rank; // Rank (position) number in the query
|
||||
SQLLEN Slen; // Used with Fetch
|
||||
int Rank; // Rank (position) number in the query
|
||||
}; // 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. */
|
||||
/***********************************************************************/
|
||||
|
@ -591,6 +591,17 @@ bool PRXCOL::Init(PGLOBAL g)
|
||||
return FALSE;
|
||||
} // 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: */
|
||||
/***********************************************************************/
|
||||
@ -600,7 +611,7 @@ void PRXCOL::ReadColumn(PGLOBAL g)
|
||||
htrc("PRX ReadColumn: name=%s\n", Name);
|
||||
|
||||
if (Colp) {
|
||||
Colp->ReadColumn(g);
|
||||
Colp->Eval(g);
|
||||
Value->SetValue_pval(To_Val);
|
||||
|
||||
// Set null when applicable
|
||||
|
@ -70,7 +70,7 @@ class DllExport TDBPRX : public TDBASE {
|
||||
virtual int GetRecpos(void) {return Tdbp->GetRecpos();}
|
||||
virtual void ResetDB(void) {Tdbp->ResetDB();}
|
||||
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
|
||||
virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
|
||||
@ -105,6 +105,7 @@ class DllExport PRXCOL : public COLBLK {
|
||||
virtual int GetAmType(void) {return TYPE_AM_PRX;}
|
||||
|
||||
// Methods
|
||||
virtual void Reset(void);
|
||||
virtual bool IsSpecial(void) {return Pseudo;}
|
||||
virtual void ReadColumn(PGLOBAL g);
|
||||
bool Init(PGLOBAL g);
|
||||
|
@ -253,7 +253,7 @@ XCLCOL::XCLCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i)
|
||||
void XCLCOL::ReadColumn(PGLOBAL g)
|
||||
{
|
||||
if (((PTDBXCL)To_Tdb)->New) {
|
||||
Colp->ReadColumn(g);
|
||||
Colp->Eval(g);
|
||||
strcpy(Cbuf, To_Val->GetCharValue());
|
||||
Cp = Cbuf;
|
||||
} // endif New
|
||||
@ -272,9 +272,11 @@ void XCLCOL::ReadColumn(PGLOBAL g)
|
||||
} else if (Nullable) {
|
||||
Value->Reset();
|
||||
Value->SetNull(true);
|
||||
} else
|
||||
} else {
|
||||
// Skip that row
|
||||
((PTDBXCL)To_Tdb)->RowFlag = 2;
|
||||
Colp->Reset();
|
||||
} // endif Cp
|
||||
|
||||
if (Cp && *Cp)
|
||||
// More to come from the same row
|
||||
|
@ -90,7 +90,7 @@ class XCLCOL : public PRXCOL {
|
||||
XCLCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i);
|
||||
|
||||
// Methods
|
||||
virtual void Reset(void) {} // Evaluated only by TDBXCL
|
||||
virtual void Reset(void) {Colp->Reset();} // Evaluated only by TDBXCL
|
||||
virtual void ReadColumn(PGLOBAL g);
|
||||
|
||||
protected:
|
||||
|
@ -78,7 +78,9 @@ XMLDEF::XMLDEF(void)
|
||||
DefNs = NULL;
|
||||
Attrib = NULL;
|
||||
Hdattr = NULL;
|
||||
Coltype = 1;
|
||||
Limit = 0;
|
||||
Header = 0;
|
||||
Xpand = false;
|
||||
Usedom = false;
|
||||
} // end of XMLDEF constructor
|
||||
@ -338,17 +340,14 @@ PCOL TDBXML::InsertSpecialColumn(PGLOBAL g, PCOL colp)
|
||||
/***********************************************************************/
|
||||
/* 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;
|
||||
PFBLOCK fp = NULL;
|
||||
PDBUSER dup = (PDBUSER)g->Activityp->Aptr;
|
||||
|
||||
/*********************************************************************/
|
||||
/* We used the file name relative to recorded datapath. */
|
||||
/*********************************************************************/
|
||||
PlugSetPath(filename, Xfile, GetPath());
|
||||
if (Docp)
|
||||
return rc; // Already done
|
||||
|
||||
if (trace)
|
||||
htrc("TDBXML: loading %s\n", filename);
|
||||
@ -397,6 +396,7 @@ int TDBXML::LoadTableFile(PGLOBAL g)
|
||||
} else
|
||||
rc = (errno == ENOENT) ? RC_NF : RC_INFO;
|
||||
|
||||
// Cannot make a Xblock until document is made
|
||||
return rc;
|
||||
} // endif Docp
|
||||
|
||||
@ -418,9 +418,8 @@ int TDBXML::LoadTableFile(PGLOBAL g)
|
||||
/***********************************************************************/
|
||||
bool TDBXML::Initialize(PGLOBAL g)
|
||||
{
|
||||
char tabpath[64];
|
||||
int rc;
|
||||
PXMLCOL colp;
|
||||
int rc;
|
||||
PXMLCOL colp;
|
||||
|
||||
if (Void)
|
||||
return false;
|
||||
@ -440,8 +439,13 @@ bool TDBXML::Initialize(PGLOBAL g)
|
||||
#else
|
||||
if (!Root) {
|
||||
#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
|
||||
rc = LoadTableFile(g);
|
||||
rc = LoadTableFile(g, filename);
|
||||
|
||||
if (rc == RC_OK) {
|
||||
// Get root node
|
||||
@ -503,6 +507,9 @@ bool TDBXML::Initialize(PGLOBAL g)
|
||||
goto error;
|
||||
} // endif NewDoc
|
||||
|
||||
// Now we can link the Xblock
|
||||
To_Xb = Docp->LinkXblock(g, Mode, rc, filename);
|
||||
|
||||
// Add a CONNECT comment node
|
||||
// sprintf(buf, MSG(CREATED_PLUGDB), version);
|
||||
sprintf(buf, " Created by CONNECT %s ", version);
|
||||
@ -893,12 +900,21 @@ int TDBXML::DeleteDB(PGLOBAL g, int irc)
|
||||
if ((RowNode = Nlist->GetItem(g, Irow, RowNode)) == NULL) {
|
||||
sprintf(g->Message, MSG(MISSING_ROWNODE), Irow);
|
||||
return RC_FX;
|
||||
} else
|
||||
} else {
|
||||
TabNode->DeleteChild(g, RowNode);
|
||||
|
||||
if (Nlist->DropItem(g, Irow))
|
||||
return RC_FX;
|
||||
|
||||
} // endif RowNode
|
||||
|
||||
Changed = true;
|
||||
} else if (irc != RC_EF) {
|
||||
TabNode->DeleteChild(g, RowNode);
|
||||
|
||||
if (Nlist->DropItem(g, Irow))
|
||||
return RC_FX;
|
||||
|
||||
Changed = true;
|
||||
} // endif's irc
|
||||
|
||||
|
@ -6,8 +6,6 @@
|
||||
/* */
|
||||
/* This file contains the XML table classes declares. */
|
||||
/***********************************************************************/
|
||||
#define TYPE_AM_XML (AMT)127
|
||||
|
||||
typedef class XMLDEF *PXMLDEF;
|
||||
typedef class TDBXML *PTDBXML;
|
||||
typedef class XMLCOL *PXMLCOL;
|
||||
@ -81,7 +79,7 @@ class DllExport TDBXML : public TDBASE {
|
||||
virtual void ResetDB(void) {N = 0;}
|
||||
virtual void ResetSize(void) {MaxSize = -1;}
|
||||
virtual int RowNumber(PGLOBAL g, bool b = false);
|
||||
int LoadTableFile(PGLOBAL g);
|
||||
int LoadTableFile(PGLOBAL g, char *filename);
|
||||
bool Initialize(PGLOBAL g);
|
||||
bool SetTabNode(PGLOBAL g);
|
||||
void SetNodeAttr(PGLOBAL g, char *attr, PXNODE node);
|
||||
|
@ -447,13 +447,12 @@ int TYPBLK<TYPE>::Find(PVAL vp)
|
||||
template <class TYPE>
|
||||
int TYPBLK<TYPE>::GetMaxLength(void)
|
||||
{
|
||||
char buf[12];
|
||||
int i, n;
|
||||
char buf[32];
|
||||
int i, n, m;
|
||||
|
||||
for (i = n = 0; i < Nval; i++) {
|
||||
sprintf(buf, Fmt, Typp[i]);
|
||||
|
||||
n = max(n, (signed)strlen(buf));
|
||||
m = sprintf(buf, Fmt, Typp[i]);
|
||||
n = max(n, m);
|
||||
} // endfor i
|
||||
|
||||
return n;
|
||||
|
Loading…
x
Reference in New Issue
Block a user