1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

Merge 10.0-connect -> 10.0

This commit is contained in:
Alexander Barkov
2013-12-03 14:12:53 +04:00
69 changed files with 3392 additions and 1765 deletions

View File

@ -166,6 +166,7 @@ my $DEFAULT_SUITES= join(',', map { "$_-" } qw(
main
archive
binlog
connect
csv
federated
funcs_1
@ -380,7 +381,6 @@ sub main {
mtr_report("Logging: $0 ", join(" ", @ARGV));
$DEFAULT_SUITES.= ',' . join(',', qw(
connect
query_response_time
sequence
spider

View File

@ -264,6 +264,19 @@ int main() {
ENDIF(UNIX)
ENDIF(CONNECT_WITH_ODBC)
#
# Installing tests
#
IF(INSTALL_MYSQLTESTDIR)
INSTALL(
DIRECTORY mysql-test/connect
DESTINATION ${INSTALL_MYSQLTESTDIR}/suite
USE_SOURCE_PERMISSIONS
COMPONENT Test
PATTERN "*~" EXCLUDE
)
ENDIF()
#
# Plugin definition

View File

@ -164,8 +164,7 @@ bool COLBLK::CheckSort(PTDB tdbp)
/* Now we use Format.Length for the len parameter to avoid strings */
/* to be truncated when converting from string to coded string. */
/* Added in version 1.5 is the arguments GetPrecision() and Domain */
/* in calling AllocateValue. Domain is used for TYPE_TOKEN only, */
/* but why was GetPrecision() not specified ? To be checked. */
/* in calling AllocateValue. Domain is used for TYPE_DATE only. */
/***********************************************************************/
bool COLBLK::InitValue(PGLOBAL g)
{
@ -174,8 +173,7 @@ bool COLBLK::InitValue(PGLOBAL g)
// Allocate a Value object
if (!(Value = AllocateValue(g, Buf_Type, Format.Length,
GetPrecision(), GetDomain(),
(To_Tdb) ? To_Tdb->GetCat() : NULL)))
GetPrecision(), GetDomain())))
return true;
AddStatus(BUF_READY);

View File

@ -251,7 +251,7 @@ bool CntOpenTable(PGLOBAL g, PTDB tdbp, MODE mode, char *c1, char *c2,
return true;
} // endif tdbp
tdbp->SetMode(mode);
//tdbp->SetMode(mode); done in ha_connect::GetTDB
if (!c1) {
if (mode == MODE_INSERT)
@ -498,8 +498,8 @@ RCODE CntDeleteRow(PGLOBAL g, PTDB tdbp, bool all)
if (!tdbp || tdbp->GetMode() != MODE_DELETE)
return RC_FX;
// else
// ((PTDBDOX)tdbp)->SetModified(true);
else if (tdbp->IsReadOnly())
return RC_NF;
if (((PTDBASE)tdbp)->GetDef()->Indexable() && all)
((PTDBDOS)tdbp)->Cardinal= 0;
@ -518,17 +518,13 @@ int CntCloseTable(PGLOBAL g, PTDB tdbp)
int rc= RC_OK;
TDBDOX *tbxp= NULL;
if (!tdbp)
return rc; // Already done
if (!tdbp || tdbp->GetUse() != USE_OPEN)
return rc; // Nothing to do
if (xtrace)
printf("CntCloseTable: tdbp=%p mode=%d\n", tdbp, tdbp->GetMode());
/*********************************************************************/
/* This will close the table file(s) and also finalize write */
/* operations such as Insert, Update, or Delete. */
/*********************************************************************/
if (tdbp->GetMode() == MODE_DELETE)
if (tdbp->GetMode() == MODE_DELETE && tdbp->GetUse() == USE_OPEN)
rc= tdbp->DeleteDB(g, RC_EF); // Specific A.M. delete routine
// Prepare error return
@ -543,6 +539,8 @@ int CntCloseTable(PGLOBAL g, PTDB tdbp)
goto err;
} // endif
// This will close the table file(s) and also finalize write
// operations such as Insert, Update, or Delete.
tdbp->CloseDB(g);
g->jump_level--;

View File

@ -17,8 +17,6 @@ typedef class BLKFAM *PBLKFAM;
typedef class DOSDEF *PDOSDEF;
typedef class TDBDOS *PTDBDOS;
#define TYPE_AM_BLK (AMT)160
/***********************************************************************/
/* This is the base class for all file access method classes. */
/***********************************************************************/

View File

@ -91,7 +91,7 @@ typedef struct _vecheader {
/* Conversion of block values allowed conditionally for insert only. */
/***********************************************************************/
PVBLK AllocValBlock(PGLOBAL, void *, int, int, int, int,
bool check = true, bool blank = true);
bool check = true, bool blank = true, bool un = false);
/* -------------------------- Class VCTFAM --------------------------- */

View File

@ -10,9 +10,6 @@
#include "zlib.h"
#define TYPE_AM_ZIP (AMT)150
#define TYPE_AM_ZLIB (AMT)155
typedef class ZIPFAM *PZIPFAM;
typedef class ZBKFAM *PZBKFAM;
typedef class ZIXFAM *PZIXFAM;

View File

@ -165,7 +165,7 @@ extern "C" char nmfile[];
extern "C" char pdebug[];
extern "C" {
char version[]= "Version 1.01.0008 August 18, 2013";
char version[]= "Version 1.01.0009 October 29, 2013";
#if defined(XMSG)
char msglang[]; // Default message language
@ -183,7 +183,7 @@ ulong ha_connect::num= 0;
//int DTVAL::Shift= 0;
static PCONNECT GetUser(THD *thd, PCONNECT xp);
static PGLOBAL GetPlug(THD *thd, PCONNECT lxp);
static PGLOBAL GetPlug(THD *thd, PCONNECT& lxp);
static handler *connect_create_handler(handlerton *hton,
TABLE_SHARE *table,
@ -258,17 +258,21 @@ ha_create_table_option connect_field_option_list[]=
/***********************************************************************/
/* Push G->Message as a MySQL warning. */
/***********************************************************************/
bool PushWarning(PGLOBAL g, PTDBASE tdbp)
bool PushWarning(PGLOBAL g, PTDBASE tdbp, int level)
{
PHC phc;
THD *thd;
MYCAT *cat= (MYCAT*)tdbp->GetDef()->GetCat();
Sql_condition::enum_warning_level wlvl;
if (!cat || !(phc= cat->GetHandler()) || !phc->GetTable() ||
!(thd= (phc->GetTable())->in_use))
return true;
push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
//push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
wlvl= (Sql_condition::enum_warning_level)level;
push_warning(thd, wlvl, 0, g->Message);
return false;
} // end of PushWarning
@ -552,7 +556,7 @@ static PCONNECT GetUser(THD *thd, PCONNECT xp)
/****************************************************************************/
/* Get the global pointer of the user of this handler. */
/****************************************************************************/
static PGLOBAL GetPlug(THD *thd, PCONNECT lxp)
static PGLOBAL GetPlug(THD *thd, PCONNECT& lxp)
{
lxp= GetUser(thd, lxp);
return (lxp) ? lxp->g : NULL;
@ -659,6 +663,8 @@ char *ha_connect::GetStringOption(char *opname, char *sdef)
opval= (char*)options->colist;
else if (!stricmp(opname, "Data_charset"))
opval= (char*)options->data_charset;
else if (!stricmp(opname, "Query_String"))
opval= thd_query_string(table->in_use)->str;
if (!opval && options && options->oplist)
opval= GetListOption(xp->g, opname, options->oplist);
@ -1096,19 +1102,20 @@ PTDB ha_connect::GetTDB(PGLOBAL g)
&& (tdbp->GetMode() == xmod
|| tdbp->GetAmType() == TYPE_AM_XML)) {
tp= tdbp;
tp->SetMode(xmod);
// tp->SetMode(xmod);
} else if ((tp= CntGetTDB(g, table_name, xmod, this)))
valid_query_id= xp->last_query_id;
else
printf("GetTDB: %s\n", g->Message);
tp->SetMode(xmod);
return tp;
} // end of GetTDB
/****************************************************************************/
/* Open a CONNECT table, restricting column list if cols is true. */
/****************************************************************************/
bool ha_connect::OpenTable(PGLOBAL g, bool del)
int ha_connect::OpenTable(PGLOBAL g, bool del)
{
bool rc= false;
char *c1= NULL, *c2=NULL;
@ -1116,11 +1123,11 @@ bool ha_connect::OpenTable(PGLOBAL g, bool del)
// Double test to be on the safe side
if (!g || !table) {
printf("OpenTable logical error; g=%p table=%p\n", g, table);
return true;
return HA_ERR_INITIALIZATION;
} // endif g
if (!(tdbp= GetTDB(g)))
return true;
return RC_FX;
else if (tdbp->IsReadOnly())
switch (xmod) {
case MODE_WRITE:
@ -1128,7 +1135,7 @@ bool ha_connect::OpenTable(PGLOBAL g, bool del)
case MODE_UPDATE:
case MODE_DELETE:
strcpy(g->Message, MSG(READ_ONLY));
return true;
return HA_ERR_TABLE_READONLY;
default:
break;
} // endswitch xmode
@ -1205,7 +1212,7 @@ bool ha_connect::OpenTable(PGLOBAL g, bool del)
valid_info= false;
} // endif rc
return rc;
return (rc) ? HA_ERR_INITIALIZATION : 0;
} // end of OpenTable
@ -1239,15 +1246,16 @@ int ha_connect::CloseTable(PGLOBAL g)
/***********************************************************************/
int ha_connect::MakeRecord(char *buf)
{
char *p, *fmt, val[32];
int rc= 0;
Field* *field;
Field *fp;
my_bitmap_map *org_bitmap;
CHARSET_INFO *charset= tdbp->data_charset();
const MY_BITMAP *map;
PVAL value;
PCOL colp= NULL;
char *p, *fmt, val[32];
int rc= 0;
Field* *field;
Field *fp;
my_bitmap_map *org_bitmap;
CHARSET_INFO *charset= tdbp->data_charset();
//MY_BITMAP readmap;
MY_BITMAP *map;
PVAL value;
PCOL colp= NULL;
DBUG_ENTER("ha_connect::MakeRecord");
if (xtrace > 1)
@ -1263,7 +1271,7 @@ int ha_connect::MakeRecord(char *buf)
memset(buf, 0, table->s->null_bytes);
// When sorting read_set selects all columns, so we use def_read_set
map= (const MY_BITMAP *)&table->def_read_set;
map= (MY_BITMAP *)&table->def_read_set;
// Make the pseudo record from field values
for (field= table->field; *field && !rc; field++) {
@ -1300,6 +1308,9 @@ int ha_connect::MakeRecord(char *buf)
case MYSQL_TYPE_TIME:
fmt= "%H:%M:%S";
break;
case MYSQL_TYPE_YEAR:
fmt= "%Y";
break;
default:
fmt= "%Y-%m-%d %H:%M:%S";
break;
@ -1401,24 +1412,25 @@ int ha_connect::ScanRecord(PGLOBAL g, uchar *buf)
value->SetValue(fp->val_real());
break;
case TYPE_DATE:
if (!sdvalin) {
if (!sdvalin)
sdvalin= (DTVAL*)AllocateValue(xp->g, TYPE_DATE, 19);
// Get date in the format produced by MySQL fields
switch (fp->type()) {
case MYSQL_TYPE_DATE:
fmt= "YYYY-MM-DD";
break;
case MYSQL_TYPE_TIME:
fmt= "hh:mm:ss";
break;
default:
fmt= "YYYY-MM-DD hh:mm:ss";
} // endswitch type
((DTVAL*)sdvalin)->SetFormat(g, fmt, strlen(fmt));
} // endif sdvalin
// Get date in the format produced by MySQL fields
switch (fp->type()) {
case MYSQL_TYPE_DATE:
fmt= "YYYY-MM-DD";
break;
case MYSQL_TYPE_TIME:
fmt= "hh:mm:ss";
break;
case MYSQL_TYPE_YEAR:
fmt= "YYYY";
break;
default:
fmt= "YYYY-MM-DD hh:mm:ss";
} // endswitch type
((DTVAL*)sdvalin)->SetFormat(g, fmt, strlen(fmt));
fp->val_str(&attribute);
sdvalin->SetValue_psz(attribute.c_ptr_safe());
value->SetValue_pval(sdvalin);
@ -1557,8 +1569,9 @@ const char *ha_connect::GetValStr(OPVAL vop, bool neg)
/***********************************************************************/
PFIL ha_connect::CheckCond(PGLOBAL g, PFIL filp, AMT tty, Item *cond)
{
char *body= filp->Body;
unsigned int i;
bool ismul= false;
bool ismul= false, x= (tty == TYPE_AM_MYX || tty == TYPE_AM_XDBC);
PPARM pfirst= NULL, pprec= NULL, pp[2]= {NULL, NULL};
OPVAL vop= OP_XX;
@ -1572,6 +1585,9 @@ PFIL ha_connect::CheckCond(PGLOBAL g, PFIL filp, AMT tty, Item *cond)
char *p1, *p2;
Item_cond *cond_item= (Item_cond *)cond;
if (x)
return NULL;
if (xtrace > 1)
printf("Cond: Ftype=%d name=%s\n", cond_item->functype(),
cond_item->func_name());
@ -1586,7 +1602,7 @@ PFIL ha_connect::CheckCond(PGLOBAL g, PFIL filp, AMT tty, Item *cond)
List_iterator<Item> li(*arglist);
Item *subitem;
p1= filp + strlen(filp);
p1= body + strlen(body);
strcpy(p1, "(");
p2= p1 + 1;
@ -1615,7 +1631,7 @@ PFIL ha_connect::CheckCond(PGLOBAL g, PFIL filp, AMT tty, Item *cond)
} else if (cond->type() == COND::FUNC_ITEM) {
unsigned int i;
// int n;
bool iscol, neg= FALSE;
bool iscol, neg= FALSE;
Item_func *condf= (Item_func *)cond;
Item* *args= condf->arguments();
@ -1644,6 +1660,9 @@ PFIL ha_connect::CheckCond(PGLOBAL g, PFIL filp, AMT tty, Item *cond)
else if (ismul && tty == TYPE_AM_WMI)
return NULL; // Not supported by WQL
if (x && (neg || !(vop == OP_EQ || vop == OP_IN)))
return NULL;
for (i= 0; i < condf->argument_count(); i++) {
if (xtrace > 1)
printf("Argtype(%d)=%d\n", i, args[i]->type());
@ -1660,6 +1679,9 @@ PFIL ha_connect::CheckCond(PGLOBAL g, PFIL filp, AMT tty, Item *cond)
ha_field_option_struct *fop;
Item_field *pField= (Item_field *)args[i];
if (x && i)
return NULL;
if (pField->field->table != table)
return NULL; // Field does not belong to this table
else
@ -1685,10 +1707,10 @@ PFIL ha_connect::CheckCond(PGLOBAL g, PFIL filp, AMT tty, Item *cond)
if (i && ismul)
return NULL;
strcat(filp, fnm);
strcat(body, fnm);
} else {
char buff[256];
String *res, tmp(buff,sizeof(buff), &my_charset_bin);
char buff[256];
String *res, tmp(buff, sizeof(buff), &my_charset_bin);
Item_basic_constant *pval= (Item_basic_constant *)args[i];
if ((res= pval->val_str(&tmp)) == NULL)
@ -1698,26 +1720,46 @@ PFIL ha_connect::CheckCond(PGLOBAL g, PFIL filp, AMT tty, Item *cond)
printf("Value=%.*s\n", res->length(), res->ptr());
// IN and BETWEEN clauses should be col VOP list
if (!i && ismul)
if (!i && (x || ismul))
return NULL;
// Append the value to the filter
if (args[i]->type() == COND::STRING_ITEM)
strcat(strcat(strcat(filp, "'"), res->ptr()), "'");
else
strncat(filp, res->ptr(), res->length());
if (!x) {
// Append the value to the filter
if (args[i]->field_type() == MYSQL_TYPE_VARCHAR)
strcat(strcat(strcat(body, "'"), res->ptr()), "'");
else
strncat(body, res->ptr(), res->length());
} else {
if (args[i]->field_type() == MYSQL_TYPE_VARCHAR) {
// Add the command to the list
PCMD *ncp, cmdp= new(g) CMD(g, (char*)res->ptr());
for (ncp= &filp->Cmds; *ncp; ncp= &(*ncp)->Next) ;
*ncp= cmdp;
} else
return NULL;
} // endif x
} // endif
if (!i)
strcat(filp, GetValStr(vop, neg));
else if (vop == OP_XX && i == 1)
strcat(filp, " AND ");
else if (vop == OP_IN)
strcat(filp, (i == condf->argument_count() - 1) ? ")" : ",");
if (!x) {
if (!i)
strcat(body, GetValStr(vop, neg));
else if (vop == OP_XX && i == 1)
strcat(body, " AND ");
else if (vop == OP_IN)
strcat(body, (i == condf->argument_count() - 1) ? ")" : ",");
} // endif x
} // endfor i
if (x)
filp->Op= vop;
} else {
if (xtrace > 1)
printf("Unsupported condition\n");
@ -1753,23 +1795,31 @@ const COND *ha_connect::cond_push(const COND *cond)
DBUG_ENTER("ha_connect::cond_push");
if (tdbp) {
AMT tty= tdbp->GetAmType();
AMT tty= tdbp->GetAmType();
bool x= (tty == TYPE_AM_MYX || tty == TYPE_AM_XDBC);
if (tty == TYPE_AM_WMI || tty == TYPE_AM_ODBC ||
tty == TYPE_AM_TBL || tty == TYPE_AM_MYSQL) {
tty == TYPE_AM_TBL || tty == TYPE_AM_MYSQL || x) {
PGLOBAL& g= xp->g;
PFIL filp= (PFIL)PlugSubAlloc(g, NULL, 0);
PFIL filp= (PFIL)PlugSubAlloc(g, NULL, sizeof(FILTER));
*filp= 0;
filp->Body= (char*)PlugSubAlloc(g, NULL, (x) ? 128 : 0);
*filp->Body= 0;
filp->Op= OP_XX;
filp->Cmds= NULL;
if (CheckCond(g, filp, tty, (Item *)cond)) {
if (xtrace)
puts(filp);
puts(filp->Body);
if (!x)
PlugSubAlloc(g, NULL, strlen(filp->Body) + 1);
else
cond= NULL; // Does this work?
tdbp->SetFilter(filp);
// cond= NULL; // This does not work anyway
PlugSubAlloc(g, NULL, strlen(filp) + 1);
} // endif filp
} else if (x && cond)
tdbp->SetFilter(filp); // Wrong filter
} // endif tty
@ -1965,14 +2015,8 @@ int ha_connect::write_row(uchar *buf)
if (IsOpened())
CloseTable(g);
if (OpenTable(g)) {
if (strstr(g->Message, "read only"))
rc= HA_ERR_TABLE_READONLY;
else
rc= HA_ERR_INITIALIZATION;
if ((rc= OpenTable(g)))
DBUG_RETURN(rc);
} // endif tdbp
} // endif isopened
@ -2337,6 +2381,7 @@ int ha_connect::index_next_same(uchar *buf, const uchar *key, uint keylen)
*/
int ha_connect::rnd_init(bool scan)
{
int rc;
PGLOBAL g= ((table && table->in_use) ? GetPlug(table->in_use, xp) :
(xp) ? xp->g : NULL);
DBUG_ENTER("ha_connect::rnd_init");
@ -2344,18 +2389,21 @@ int ha_connect::rnd_init(bool scan)
if (xtrace)
printf("%p in rnd_init: scan=%d\n", this, scan);
if (g) {
if (!table || xmod == MODE_INSERT)
DBUG_RETURN(HA_ERR_INITIALIZATION);
if (!g || !table || xmod == MODE_INSERT)
DBUG_RETURN(HA_ERR_INITIALIZATION);
// Close the table if it was opened yet (locked?)
if (IsOpened())
CloseTable(g);
// Close the table if it was opened yet (locked?)
if (IsOpened())
CloseTable(g);
if (OpenTable(g, xmod == MODE_DELETE))
DBUG_RETURN(HA_ERR_INITIALIZATION);
// When updating, to avoid skipped update, force the table
// handler to retrieve write-only fields to be able to compare
// records and detect data change.
if (xmod == MODE_UPDATE)
bitmap_union(table->read_set, table->write_set);
} // endif g
if ((rc= OpenTable(g, xmod == MODE_DELETE)))
DBUG_RETURN(rc);
xp->nrd= xp->fnd= xp->nfd= 0;
xp->tb1= my_interval_timer();
@ -2566,7 +2614,6 @@ int ha_connect::info(uint flag)
xp->CheckCleanup();
} // endif xmod
// tdbp= OpenTable(g, xmod == MODE_DELETE);
tdbp= GetTDB(g);
} // endif tdbp
@ -2661,18 +2708,19 @@ int ha_connect::delete_all_rows()
PGLOBAL g= xp->g;
DBUG_ENTER("ha_connect::delete_all_rows");
if (tdbp && tdbp->GetAmType() != TYPE_AM_XML)
if (tdbp && tdbp->GetUse() == USE_OPEN &&
tdbp->GetAmType() != TYPE_AM_XML &&
((PTDBASE)tdbp)->GetFtype() != RECFM_NAF)
// Close and reopen the table so it will be deleted
rc= CloseTable(g);
if (!(OpenTable(g))) {
if (!(rc= OpenTable(g))) {
if (CntDeleteRow(g, tdbp, true)) {
printf("%s\n", g->Message);
rc= HA_ERR_INTERNAL_ERROR;
} // endif
} else
rc= HA_ERR_INITIALIZATION;
} // endif rc
DBUG_RETURN(rc);
} // end of delete_all_rows
@ -3461,12 +3509,13 @@ static bool add_fields(PGLOBAL g,
DBUG_RETURN(0);
} // end of add_fields
#else // !NEW_WAY
static bool add_field(String *sql, const char *field_name, int typ, int len,
int dec, uint tm, const char *rem, int flag, bool dbf)
static bool add_field(String *sql, const char *field_name, int typ,
int len, int dec, uint tm, const char *rem,
int flag, bool dbf, char v)
{
char var = (len > 255) ? 'V' : v;
bool error= false;
const char *type= PLGtoMYSQLtype(typ, dbf);
// type= PLGtoMYSQLtype(typ, true); ?????
const char *type= PLGtoMYSQLtype(typ, dbf, var);
error|= sql->append('`');
error|= sql->append(field_name);
@ -3479,7 +3528,8 @@ static bool add_field(String *sql, const char *field_name, int typ, int len,
if (!strcmp(type, "DOUBLE")) {
error|= sql->append(',');
error|= sql->append_ulonglong(dec);
// dec must be <= len and <= 31
error|= sql->append_ulonglong(min(dec, (len - 1)));
} // endif dec
error|= sql->append(')');
@ -3518,6 +3568,8 @@ static int init_table_share(THD *thd,
HA_CREATE_INFO *create_info,
Alter_info *alter_info)
{
KEY *not_used_1;
uint not_used_2;
int rc= 0;
handler *file;
LEX_CUSTRING frm= {0,0};
@ -3577,9 +3629,8 @@ static int init_table_share(THD *thd,
tmp_disable_binlog(thd);
file= mysql_create_frm_image(thd, table_s->db.str, table_s->table_name.str,
create_info, alter_info,
// &thd->lex->create_info, &thd->lex->alter_info,
C_ORDINARY_CREATE, &frm);
create_info, alter_info, C_ORDINARY_CREATE,
&not_used_1, &not_used_2, &frm);
if (file)
delete file;
else
@ -3772,13 +3823,14 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
TABTYPE ttp= TAB_UNDEF;
PQRYRES qrp= NULL;
PCOLRES crp;
PGLOBAL g= GetPlug(thd, NULL);
PCONNECT xp= NULL;
PGLOBAL g= GetPlug(thd, xp);
PTOS topt= table_s->option_struct;
#if defined(NEW_WAY)
//CHARSET_INFO *cs;
Alter_info alter_info;
#else // !NEW_WAY
char buf[1024];
char v, buf[1024];
String sql(buf, sizeof(buf), system_charset_info);
sql.copy(STRING_WITH_LEN("CREATE TABLE whatever ("), system_charset_info);
@ -3821,7 +3873,9 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
#endif // WIN32
port= atoi(GetListOption(g, "port", topt->oplist, "0"));
mxr= atoi(GetListOption(g,"maxerr", topt->oplist, "0"));
#if defined(PROMPT_OK)
cop= atoi(GetListOption(g, "checkdsn", topt->oplist, "0"));
#endif // PROMPT_OK
} else {
host= "localhost";
user= "root";
@ -3879,14 +3933,16 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
case TAB_ODBC:
dsn= create_info->connect_string.str;
if (fnc & (FNC_DSN | FNC_DRIVER))
if (fnc & (FNC_DSN | FNC_DRIVER)) {
ok= true;
else if (!stricmp(thd->main_security_ctx.host, "localhost")
#if defined(PROMPT_OK)
} else if (!stricmp(thd->main_security_ctx.host, "localhost")
&& cop == 1) {
if ((dsn = ODBCCheckConnection(g, dsn, cop)) != NULL) {
thd->make_lex_string(&create_info->connect_string, dsn, strlen(dsn));
ok= true;
} // endif dsn
#endif // PROMPT_OK
} else if (!dsn)
sprintf(g->Message, "Missing %s connection string", topt->type);
@ -4098,7 +4154,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
NOT_NULL_FLAG, "", flg, dbf);
#else // !NEW_WAY
// Now add the field
if (add_field(&sql, cnm, typ, len, dec, NOT_NULL_FLAG, 0, flg, dbf))
if (add_field(&sql, cnm, typ, len, dec, NOT_NULL_FLAG, 0, flg, dbf, 0))
rc= HA_ERR_OUT_OF_MEM;
#endif // !NEW_WAY
} // endfor crp
@ -4122,6 +4178,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
break;
case FLD_TYPE:
typ= crp->Kdata->GetIntValue(i);
v = (crp->Nulls) ? crp->Nulls[i] : 0;
break;
case FLD_PREC:
len= crp->Kdata->GetIntValue(i);
@ -4152,7 +4209,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
int plgtyp;
// typ must be PLG type, not SQL type
if (!(plgtyp= TranslateSQLType(typ, dec, len))) {
if (!(plgtyp= TranslateSQLType(typ, dec, len, v))) {
sprintf(g->Message, "Unsupported SQL type %d", typ);
my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
return HA_ERR_INTERNAL_ERROR;
@ -4177,7 +4234,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
rc= add_fields(g, thd, &alter_info, cnm, typ, len, dec,
tm, rem, 0, true);
#else // !NEW_WAY
if (add_field(&sql, cnm, typ, len, dec, tm, rem, 0, true))
if (add_field(&sql, cnm, typ, len, dec, tm, rem, 0, dbf, v))
rc= HA_ERR_OUT_OF_MEM;
#endif // !NEW_WAY
} // endfor i
@ -4671,6 +4728,6 @@ maria_declare_plugin(connect)
NULL, /* status variables */
NULL, /* system variables */
"0.1", /* string version */
MariaDB_PLUGIN_MATURITY_EXPERIMENTAL /* maturity */
MariaDB_PLUGIN_MATURITY_ALPHA /* maturity */
}
maria_declare_plugin_end;

View File

@ -174,7 +174,7 @@ public:
bool IsSameIndex(PIXDEF xp1, PIXDEF xp2);
PTDB GetTDB(PGLOBAL g);
bool OpenTable(PGLOBAL g, bool del= false);
int OpenTable(PGLOBAL g, bool del= false);
bool IsOpened(void);
int CloseTable(PGLOBAL g);
int MakeRecord(char *buf);

View File

@ -8,6 +8,9 @@
#include <libxml/tree.h>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>
#include <libxml/catalog.h>
#include <libxml/xmlschemastypes.h>
#include <libxml/relaxng.h>
//#if defined(WIN32)
//#include <windows.h>
//#else // !WIN32
@ -290,10 +293,46 @@ if (!rc)
/******************************************************************/
/* XML library cleanup function. */
/******************************************************************/
/*
This is a copy of xmlCleanupParser() from the libxml2 sources
with xmlResetLastError() commented.
xmlResetLastError() called from the original xmlCleanupParser() causes
valgrind to report memory leaks. This happens because
ha_initialize_handlerton() is called from the main thread in mysqld.cc,
while ha_finalize_handlerton() is called from a non-main thread.
libxml2 gets confused because of xmlInitParser() and xmlCleanupParser()
being called from the different threads.
Perhaps the code in mysqld.cc should eventually be modified
to shutdown plugins from the main thread.
*/
static void
xmlCleanupParser_replacement(void)
{
xmlCleanupCharEncodingHandlers();
#ifdef LIBXML_CATALOG_ENABLED
xmlCatalogCleanup();
#endif
xmlDictCleanup();
xmlCleanupInputCallbacks();
#ifdef LIBXML_OUTPUT_ENABLED
xmlCleanupOutputCallbacks();
#endif
#ifdef LIBXML_SCHEMAS_ENABLED
xmlSchemaCleanupTypes();
xmlRelaxNGCleanupTypes();
#endif
//xmlResetLastError();
xmlCleanupGlobals();
xmlCleanupThreads(); /* must be last if called not from the main thread */
xmlCleanupMemory();
}
void XmlCleanupParserLib(void)
{
xmlCleanupParser();
xmlMemoryDump();
xmlCleanupParser_replacement();
} // end of XmlCleanupParserLib
/******************************************************************/

View File

@ -87,7 +87,7 @@ PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db,
FLD_KEY, FLD_SCALE, FLD_RADIX, FLD_NULL,
FLD_REM, FLD_NO, FLD_CHARSET};
static unsigned int length[] = {0, 4, 16, 4, 4, 4, 4, 4, 256, 32, 32};
char *fld, *fmt, cmd[128];
char *fld, *fmt, v, cmd[128];
int i, n, nf, ncol = sizeof(buftyp) / sizeof(int);
int len, type, prec, rc, k = 0;
PQRYRES qrp;
@ -139,6 +139,7 @@ PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db,
// Some columns must be renamed
for (i = 0, crp = qrp->Colresp; crp; crp = crp->Next)
switch (++i) {
case 2: crp->Nulls = (char*)PlugSubAlloc(g, NULL, n); break;
case 4: crp->Name = "Length"; break;
case 5: crp->Name = "Key"; break;
case 10: crp->Name = "Date_fmt"; break;
@ -166,7 +167,8 @@ PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db,
// Get type, type name, and precision
fld = myc.GetCharField(1);
prec = 0;
len = 255; // Default for text or blob
len = 0;
v = 0;
if ((nf = sscanf(fld, "%[^(](%d,%d", cmd, &len, &prec)) < 1) {
sprintf(g->Message, MSG(BAD_FIELD_TYPE), fld);
@ -175,14 +177,16 @@ PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db,
} else
qrp->Nblin++;
if ((type = MYSQLtoPLG(cmd)) == TYPE_ERROR) {
if ((type = MYSQLtoPLG(cmd, &v)) == TYPE_ERROR) {
sprintf(g->Message, "Unsupported column type %s", cmd);
myc.Close();
return NULL;
} // endif type
} else if (type == TYPE_STRING)
len = min(len, 4096);
crp = crp->Next; // Data_Type
crp->Kdata->SetValue(type, i);
crp->Nulls[i] = v;
crp = crp->Next; // Type_Name
crp->Kdata->SetValue(cmd, i);
@ -253,6 +257,7 @@ PQRYRES SrcColumns(PGLOBAL g, const char *host, const char *db,
const char *user, const char *pwd,
const char *srcdef, int port)
{
char *query;
int w;
MYSQLC myc;
PQRYRES qrp = NULL;
@ -260,12 +265,15 @@ PQRYRES SrcColumns(PGLOBAL g, const char *host, const char *db,
if (!port)
port = mysqld_port;
query = (char *)PlugSubAlloc(g, NULL, strlen(srcdef) + 9);
strcat(strcpy(query, srcdef), " LIMIT 0");
// Open a MySQL connection for this table
if (myc.Open(g, host, db, user, pwd, port))
return NULL;
// Send the source command to MySQL
if (myc.ExecSQL(g, srcdef, &w) == RC_OK)
if (myc.ExecSQL(g, query, &w) == RC_OK)
qrp = myc.GetResult(g);
myc.Close();
@ -701,7 +709,7 @@ PQRYRES MYSQLC::GetResult(PGLOBAL g, bool pdb)
crp->Clen = GetTypeSize(crp->Type, crp->Length);
if (!(crp->Kdata = AllocValBlock(g, NULL, crp->Type, m_Rows,
crp->Clen, 0, FALSE, TRUE))) {
crp->Clen, 0, FALSE, TRUE, FALSE))) {
sprintf(g->Message, MSG(INV_RESULT_TYPE),
GetFormatType(crp->Type));
return NULL;
@ -778,6 +786,42 @@ void MYSQLC::Rewind(void)
} // end of Rewind
/***********************************************************************/
/* Exec the Select SQL command and return ncol or afrws (TDBMYEXC). */
/***********************************************************************/
int MYSQLC::ExecSQLcmd(PGLOBAL g, const char *query, int *w)
{
int rc = RC_OK;
if (!m_DB) {
strcpy(g->Message, "MySQL not connected");
return RC_FX;
} else
*w = 0;
if (!stricmp(query, "Warning") || !stricmp(query, "Note")
|| !stricmp(query, "Error"))
return RC_INFO;
else
m_Afrw = 0;
//if (mysql_query(m_DB, query) != 0) {
if (mysql_real_query(m_DB, query, strlen(query))) {
m_Afrw = (int)mysql_errno(m_DB);
sprintf(g->Message, "Remote: %s", mysql_error(m_DB));
rc = RC_FX;
//} else if (!(m_Fields = mysql_field_count(m_DB))) {
} else if (!(m_Fields = (int)m_DB->field_count)) {
// m_Afrw = (int)mysql_affected_rows(m_DB);
m_Afrw = (int)m_DB->affected_rows;
rc = RC_NF;
} // endif's
//*w = mysql_warning_count(m_DB);
*w = m_DB->warning_count;
return rc;
} // end of ExecSQLcmd
/***********************************************************************/
/* Close the connection. */
/***********************************************************************/

View File

@ -26,7 +26,6 @@
#define DllItem
#endif // !WIN32
//#define TYPE_AM_MYSQL (AMT)192
#define MYSQL_ENABLED 0x00000001
#define MYSQL_LOGON 0x00000002
@ -75,9 +74,12 @@ class DllItem MYSQLC {
//const char *ServerInfo(void);
int KillQuery(ulong id);
int ExecSQL(PGLOBAL g, const char *query, int *w = NULL);
int ExecSQLcmd(PGLOBAL g, const char *query, int *w);
#if defined(MYSQL_PREPARED_STATEMENTS)
int PrepareSQL(PGLOBAL g, const char *query);
int ExecStmt(PGLOBAL g);
int BindParams(PGLOBAL g, MYSQL_BIND *bind);
#endif // MYSQL_PREPARED_STATEMENTS
PQRYRES GetResult(PGLOBAL g, bool pdb = FALSE);
int Fetch(PGLOBAL g, int pos);
char *GetCharField(int i);
@ -99,5 +101,6 @@ class DllItem MYSQLC {
int m_Rows; // The number of rows of the result
int N;
int m_Fields; // The number of result fields
int m_Afrw; // The number of affected rows
}; // end of class MYSQLC

View File

@ -0,0 +1,15 @@
# Use default setting for mysqld processes
!include include/default_mysqld.cnf
!include include/default_client.cnf
[mysqld.1]
#log-bin= master-bin
[mysqld.2]
[ENV]
MASTER_MYPORT= @mysqld.1.port
MASTER_MYSOCK= @mysqld.1.socket
SLAVE_MYPORT= @mysqld.2.port
SLAVE_MYSOCK= @mysqld.2.socket

View File

@ -48,7 +48,7 @@ salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='F',
dept INT(4) NOT NULL FIELD_FORMAT='S'
) ENGINE=CONNECT TABLE_TYPE=BIN READONLY=Yes FILE_NAME='Testbal.dat';
INSERT INTO t1 VALUES (7777,'BILL','1973-06-30',4444,5555.555,777);
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
ALTER TABLE t1 READONLY=NO;
Warnings:
Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk
@ -84,7 +84,7 @@ t1 CREATE TABLE `t1` (
`dept` int(4) NOT NULL `FIELD_FORMAT`='S'
) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=BIN `FILE_NAME`='Testbal.dat' `READONLY`=YES
INSERT INTO t1 VALUES (7777,'BILL','1973-06-30',4444,5555.555,777);
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
DROP TABLE t1;
#
# Testing that the underlying file is created

View File

@ -50,13 +50,13 @@ children SMALLINT(2) NOT NULL
) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='people.csv'
HEADER=1 SEP_CHAR=';' QUOTED=1 READONLY=yes;
INSERT INTO t1 VALUES ('BILL','1973-06-30',5);
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
UPDATE t1 SET children=6 WHERE name='BILL';
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
DELETE FROM t1 WHERE name='BILL';
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
TRUNCATE TABLE t1;
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
SELECT * FROM t1;
name birth children
Archibald 2001-05-17 3
@ -90,7 +90,7 @@ t1 CREATE TABLE `t1` (
`children` smallint(2) NOT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=CSV `FILE_NAME`='people.csv' `HEADER`=1 `SEP_CHAR`=';' `QUOTED`=1 `READONLY`=1
INSERT INTO t1 VALUES ('BILL','1973-06-30',5);
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
SELECT * FROM t1;
name birth children
Archibald 2001-05-17 3

View File

@ -77,13 +77,13 @@ t1 CREATE TABLE `t1` (
`a` int(11) NOT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=DBF `FILE_NAME`='t1.dbf' `READONLY`=Yes
INSERT INTO t1 VALUES (30);
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
UPDATE t1 SET a=30 WHERE a=10;
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
DELETE FROM t1 WHERE a=10;
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
TRUNCATE TABLE t1;
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
ALTER TABLE t1 READONLY=NO;
Warnings:
Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk

View File

@ -30,13 +30,13 @@ t1 CREATE TABLE `t1` (
`id` int(11) NOT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=FIX `FILE_NAME`='t1.txt' `READONLY`=1
INSERT INTO t1 VALUES (20);
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
UPDATE t1 SET id=20 WHERE id=10;
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
DELETE FROM t1 WHERE id=10;
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
TRUNCATE TABLE t1;
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
ALTER TABLE t1 READONLY=0;
Warnings:
Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk

View File

@ -194,13 +194,13 @@ t1 CREATE TABLE `t1` (
`c2` char(60) DEFAULT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=INI `FILE_NAME`='t1.ini' `READONLY`=1
INSERT INTO t1 VALUES ('US',40);
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
UPDATE t1 SET c2=20 WHERE c2=10;
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
DELETE FROM t1 WHERE c2=10;
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
TRUNCATE TABLE t1;
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
ALTER TABLE t1 READONLY=0;
Warnings:
Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk

View File

@ -44,7 +44,7 @@ SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`a` int(11) DEFAULT NULL,
`b` varchar(10) DEFAULT NULL
`b` char(10) DEFAULT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='MYSQL' `TABNAME`='t1' `OPTION_LIST`='host=localhost,user=root,port=PORT'
SELECT * FROM t2;
a b
@ -176,7 +176,7 @@ t1 CREATE TABLE `t1` (
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`a` varchar(10) DEFAULT NULL
`a` char(10) DEFAULT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='MYSQL' `TABNAME`='t1' `OPTION_LIST`='host=localhost,user=root,port=PORT'
SELECT * FROM t2;
a

View File

@ -0,0 +1,42 @@
CREATE DATABASE connect;
CREATE DATABASE connect;
CREATE TABLE t1 (
`id` int(20) primary key,
`group` int NOT NULL default 1,
`a\\b` int NOT NULL default 2,
`a\\` int unsigned,
`name` varchar(32) default 'name')
DEFAULT CHARSET=latin1;
CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test/t1';
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`id` int(20) NOT NULL,
`group` int(11) NOT NULL,
`a\\b` int(11) NOT NULL,
`a\\` int(10) DEFAULT NULL,
`name` varchar(32) DEFAULT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test/t1' `TABLE_TYPE`='MYSQL'
INSERT INTO t1 (id, name) VALUES (1, 'foo');
Warnings:
Warning 1364 Field 'group' doesn't have a default value
Warning 1364 Field 'a\\b' doesn't have a default value
INSERT INTO t1 (id, name) VALUES (2, 'fee');
Warnings:
Warning 1364 Field 'group' doesn't have a default value
Warning 1364 Field 'a\\b' doesn't have a default value
SELECT * FROM t1;
id group a\\b a\\ name
1 1 2 NULL foo
2 1 2 NULL fee
DROP TABLE t1;
SELECT * FROM t1;
id group a\\b a\\ name
1 1 2 NULL foo
2 1 2 NULL fee
DROP TABLE t1;
DROP TABLE IF EXISTS connect.t1;
DROP DATABASE IF EXISTS connect;
DROP TABLE IF EXISTS connect.t1;
DROP DATABASE IF EXISTS connect;

View File

@ -0,0 +1,62 @@
CREATE DATABASE connect;
CREATE DATABASE connect;
#
# Checking Sending Commands
#
CREATE TABLE t1 (
command VARCHAR(128) NOT NULL,
warnings INT(4) NOT NULL FLAG=3,
number INT(5) NOT NULL FLAG=1,
message VARCHAR(255) FLAG=2)
ENGINE=CONNECT TABLE_TYPE=MYSQL CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test' OPTION_LIST='Execsrc=1,maxerr=2';
SELECT * FROM t1 WHERE command IN ('Warning','Note',
'drop table if exists t1',
'create table t1 (id int key auto_increment, msg varchar(32) not null)',
"insert into t1(msg) values('One'),(NULL),('Three')",
"insert into t1 values(2,'Deux') on duplicate key update msg = 'Two'",
"insert into t1(message) values('Four'),('Five'),('Six')",
'insert into t1(id) values(NULL)',
"update t1 set msg = 'Four' where id = 4",
'select * from t1');
command warnings number message
drop table if exists t1 1 0 Affected rows
Note 0 1051 Unknown table 'test.t1'
create table t1 (id int key auto_increment, msg varchar(32) not null) 0 0 Affected rows
insert into t1(msg) values('One'),(NULL),('Three') 1 3 Affected rows
Warning 0 1048 Column 'msg' cannot be null
insert into t1 values(2,'Deux') on duplicate key update msg = 'Two' 0 2 Affected rows
insert into t1(message) values('Four'),('Five'),('Six') 0 1054 Remote: Unknown column 'message' in 'field list'
insert into t1(id) values(NULL) 1 1 Affected rows
Warning 0 1364 Field 'msg' doesn't have a default value
update t1 set msg = 'Four' where id = 4 0 1 Affected rows
select * from t1 0 2 Result set columns
#
# Checking Using Procedure
#
DROP PROCEDURE IF EXISTS p1;
Warnings:
Note 1305 PROCEDURE test.p1 does not exist
CREATE PROCEDURE p1(cmd varchar(512))
READS SQL DATA
SELECT * FROM t1 WHERE command IN ('Warning','Note',cmd);
CALL p1('insert into t1(id) values(NULL)');
command warnings number message
insert into t1(id) values(NULL) 1 1 Affected rows
Warning 0 1364 Field 'msg' doesn't have a default value
CALL p1('update t1 set msg = "Five" where id = 5');
command warnings number message
update t1 set msg = "Five" where id = 5 0 1 Affected rows
DROP PROCEDURE p1;
DROP TABLE t1;
SELECT * FROM t1;
id msg
1 One
2 Two
3 Three
4 Four
5 Five
DROP TABLE t1;
DROP TABLE IF EXISTS connect.t1;
DROP DATABASE IF EXISTS connect;
DROP TABLE IF EXISTS connect.t1;
DROP DATABASE IF EXISTS connect;

View File

@ -0,0 +1,218 @@
CREATE DATABASE connect;
CREATE DATABASE connect;
CREATE TABLE t1 (a int, b char(10));
INSERT INTO t1 VALUES (NULL,NULL),(0,'test00'),(1,'test01'),(2,'test02'),(3,'test03');
SELECT * FROM t1;
a b
NULL NULL
0 test00
1 test01
2 test02
3 test03
#
# Testing errors
#
CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
CONNECTION='mysql://unknown@127.0.0.1:SLAVE_PORT/test/t1';
ERROR HY000: (1045) Access denied for user 'unknown'@'localhost' (using password: NO)
CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/unknown/t1';
ERROR HY000: (1049) Unknown database 'unknown'
CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
OPTION_LIST='host=127.0.0.1,user=root,port=SLAVE_PORT' DBNAME='unknown' TABNAME='t1';
ERROR HY000: (1049) Unknown database 'unknown'
CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test/unknown';
ERROR HY000: (1146) Table 'test.unknown' doesn't exist [SHOW FULL COLUMNS FROM unknown FROM test]
SHOW CREATE TABLE t1;
ERROR 42S02: Table 'test.t1' doesn't exist
CREATE TABLE t1 (x int, y char(10)) ENGINE=CONNECT TABLE_TYPE=MYSQL
CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test/t1';
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`x` int(11) DEFAULT NULL,
`y` char(10) DEFAULT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test/t1' `TABLE_TYPE`=MYSQL
SELECT * FROM t1;
ERROR HY000: Got error 174 '(1054) Unknown column 'x' in 'field list' [SELECT `x`, `y` FROM `t1`]' from CONNECT
DROP TABLE t1;
CREATE TABLE t1 (a int, b char(10)) ENGINE=CONNECT TABLE_TYPE=MYSQL
CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test/t1';
ALTER TABLE t1 RENAME t1backup;
SELECT * FROM t1;
ERROR HY000: Got error 174 '(1146) Table 'test.t1' doesn't exist [SELECT `a`, `b` FROM `t1`]' from CONNECT
ALTER TABLE t1backup RENAME t1;
DROP TABLE t1;
#
# Testing SELECT, etc.
#
CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test/t1';
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` int(11) DEFAULT NULL,
`b` char(10) DEFAULT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test/t1' `TABLE_TYPE`='MYSQL'
SELECT * FROM t1;
a b
NULL NULL
0 test00
1 test01
2 test02
3 test03
DROP TABLE t1;
CREATE TABLE t1 (a int, b char(10)) ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1'
OPTION_LIST='host=127.0.0.1,user=root,port=SLAVE_PORT';
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` int(11) DEFAULT NULL,
`b` char(10) DEFAULT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=MYSQL `TABNAME`='t1' `OPTION_LIST`='host=127.0.0.1,user=root,port=SLAVE_PORT'
SELECT * FROM t1;
a b
NULL NULL
0 test00
1 test01
2 test02
3 test03
DROP TABLE t1;
CREATE TABLE t1 (a INT NOT NULL, b CHAR(10) NOT NULL) ENGINE=CONNECT TABLE_TYPE=MYSQL
OPTION_LIST='host=127.0.0.1,user=root,port=SLAVE_PORT';
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` int(11) NOT NULL,
`b` char(10) NOT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=MYSQL `OPTION_LIST`='host=127.0.0.1,user=root,port=SLAVE_PORT'
SELECT * FROM t1;
a b
0
0 test00
1 test01
2 test02
3 test03
DROP TABLE t1;
CREATE TABLE t1 (a char(10), b int) ENGINE=CONNECT TABLE_TYPE=MYSQL
CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test/t1';
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` char(10) DEFAULT NULL,
`b` int(11) DEFAULT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test/t1' `TABLE_TYPE`=MYSQL
SELECT * FROM t1;
a b
NULL NULL
0 0
1 0
2 0
3 0
DROP TABLE t1;
DROP TABLE t1;
#
# Testing numeric data types
#
CREATE TABLE t1 (a tinyint, b smallint, c mediumint, d int, e bigint, f float, g double, h decimal(20,5));
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` tinyint(4) DEFAULT NULL,
`b` smallint(6) DEFAULT NULL,
`c` mediumint(9) DEFAULT NULL,
`d` int(11) DEFAULT NULL,
`e` bigint(20) DEFAULT NULL,
`f` float DEFAULT NULL,
`g` double DEFAULT NULL,
`h` decimal(20,5) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
INSERT INTO t1 VALUES(100,3333,41235,1234567890,235000000000,3.14159265,3.14159265,3141.59265);
CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
OPTION_LIST='host=127.0.0.1,user=root,port=SLAVE_PORT';
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` tinyint(4) DEFAULT NULL,
`b` smallint(6) DEFAULT NULL,
`c` int(9) DEFAULT NULL,
`d` int(11) DEFAULT NULL,
`e` bigint(20) DEFAULT NULL,
`f` double DEFAULT NULL,
`g` double DEFAULT NULL,
`h` double(20,5) DEFAULT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='MYSQL' `OPTION_LIST`='host=127.0.0.1,user=root,port=SLAVE_PORT'
SELECT * FROM t1;
a b c d e f g h
100 3333 41235 1234567890 235000000000 3.14159 3.14159265 3141.59265
DROP TABLE t1;
DROP TABLE t1;
#
# Testing character data types
#
CREATE TABLE t1 (a char(12), b varchar(12));
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` char(12) DEFAULT NULL,
`b` varchar(12) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
INSERT INTO t1 VALUES('Welcome','Hello, World');
SELECT * FROM t1;
a b
Welcome Hello, World
CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT';
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` char(12) DEFAULT NULL,
`b` varchar(12) DEFAULT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT' `TABLE_TYPE`='MYSQL'
SELECT * FROM t1;
a b
Welcome Hello, World
DROP TABLE t1;
DROP TABLE t1;
#
# Testing temporal data types
#
CREATE TABLE t1 (a date, b datetime, c time, d timestamp, e year);
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` date DEFAULT NULL,
`b` datetime DEFAULT NULL,
`c` time DEFAULT NULL,
`d` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`e` year(4) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
INSERT INTO t1 VALUES('2003-05-27 10:45:23','2003-05-27 10:45:23','2003-05-27 10:45:23','2003-05-27 10:45:23','2003-05-27 10:45:23');
Warnings:
Note 1265 Data truncated for column 'a' at row 1
Note 1265 Data truncated for column 'c' at row 1
Warning 1265 Data truncated for column 'e' at row 1
SELECT * FROM t1;
a b c d e
2003-05-27 2003-05-27 10:45:23 10:45:23 2003-05-27 10:45:23 2003
CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT';
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` date DEFAULT NULL,
`b` datetime DEFAULT NULL,
`c` time DEFAULT NULL,
`d` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`e` year(4) DEFAULT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT' `TABLE_TYPE`='MYSQL'
SELECT * FROM t1;
a b c d e
2003-05-27 2003-05-27 10:45:23 10:45:23 2003-05-27 10:45:23 2003
DROP TABLE t1;
DROP TABLE t1;
DROP TABLE IF EXISTS connect.t1;
DROP DATABASE IF EXISTS connect;
DROP TABLE IF EXISTS connect.t1;
DROP DATABASE IF EXISTS connect;

View File

@ -1,6 +1,6 @@
Table Create Table
t1 CREATE TABLE `t1` (
`Description` varchar(128) NOT NULL,
`Description` char(128) NOT NULL,
`Attributes` varchar(256) NOT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='ODBC' `CATFUNC`='Drivers'
SET NAMES utf8;
@ -41,3 +41,13 @@ test2
ÆÇÈÉË
DROP VIEW v1;
DROP TABLE t1;
CREATE TABLE t1 ENGINE=CONNECT CATFUNC=Columns TABNAME='t1' TABLE_TYPE=ODBC CONNECTION='Driver=SQLite3 ODBC Driver;Database=MTR_SUITE_DIR/std_data/test.sqlite3;NoWCHAR=yes' CHARSET=utf8 DATA_CHARSET=utf8;
SELECT * FROM t1;
Table_Qualif Table_Owner Table_Name Column_Name Data_Type Type_Name Precision Length Scale Radix Nullable Remarks
t1 a 12 varchar(64) 64 64 10 0 1
DROP TABLE t1;
CREATE TABLE t1 ENGINE=CONNECT CATFUNC=Tables TABNAME='t1' TABLE_TYPE=ODBC CONNECTION='Driver=SQLite3 ODBC Driver;Database=MTR_SUITE_DIR/std_data/test.sqlite3;NoWCHAR=yes' CHARSET=utf8 DATA_CHARSET=utf8;
SELECT * FROM t1;
Table_Qualifier Table_Owner Table_Name Table_Type Remark
t1 TABLE
DROP TABLE t1;

View File

@ -1,6 +1,6 @@
Table Create Table
t1 CREATE TABLE `t1` (
`Description` varchar(128) NOT NULL,
`Description` char(128) NOT NULL,
`Attributes` varchar(256) NOT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='ODBC' `CATFUNC`='Drivers'
SET NAMES utf8;

View File

@ -13,3 +13,14 @@ Thomas Dominique NULL
Lemonnier Nathalie Directeur Marketing Client
Menseau Eric NULL
DROP TABLE contact;
CREATE TABLE t1 ENGINE=CONNECT CATFUNC=Tables TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineXLS;DBQ=DATADIR/test/contacts.xls' CHARSET=utf8 DATA_CHARSET=latin1;;
SELECT * FROM t1 WHERE Table_name='CONTACT';
Table_Qualifier Table_Owner Table_Name Table_Type Remark
DATADIR/test/contacts CONTACT TABLE
DROP TABLE t1;
CREATE TABLE t1 ENGINE=CONNECT CATFUNC=Columns TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineXLS;DBQ=DATADIR/test/contacts.xls' CHARSET=utf8 DATA_CHARSET=latin1;;
SELECT * FROM t1 WHERE Table_name='CONTACT' AND Column_name IN ('Nom','Fonction');
Table_Qualif Table_Owner Table_Name Column_Name Data_Type Type_Name Precision Length Scale Radix Nullable Remarks
DATADIR/test/contacts CONTACT Nom 12 VARCHAR 255 510 0 0 1
DATADIR/test/contacts CONTACT Fonction 12 VARCHAR 255 510 0 0 1
DROP TABLE t1;

View File

@ -103,13 +103,13 @@ t1 CREATE TABLE `t1` (
`b` char(10) NOT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 MAX_ROWS=10 `TABLE_TYPE`=VEC `FILE_NAME`='t1vec' `READONLY`=yes
INSERT INTO t1 VALUES (4,'test04');
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
UPDATE t1 SET b='test04' WHERE a=3;
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
DELETE FROM t1 WHERE a=3;
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
TRUNCATE TABLE t1;
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
ALTER TABLE t1 READONLY=no;
Warnings:
Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk

View File

@ -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.0008 August 18, 2013 -->
<!-- Created by CONNECT Version 1.01.0009 October 29, 2013 -->
<t1>
<line>
<node>ÀÁÂÃ</node>

View File

@ -46,7 +46,7 @@ CREATE TABLE t1
salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='F',
dept INT(4) NOT NULL FIELD_FORMAT='S'
) ENGINE=CONNECT TABLE_TYPE=BIN READONLY=Yes FILE_NAME='Testbal.dat';
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
INSERT INTO t1 VALUES (7777,'BILL','1973-06-30',4444,5555.555,777);
ALTER TABLE t1 READONLY=NO;
SHOW CREATE TABLE t1;
@ -54,7 +54,7 @@ INSERT INTO t1 VALUES (7777,'BILL','1973-06-30',4444,5555.555,777);
SELECT * FROM t1;
ALTER TABLE t1 READONLY=YES;
SHOW CREATE TABLE t1;
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
INSERT INTO t1 VALUES (7777,'BILL','1973-06-30',4444,5555.555,777);
DROP TABLE t1;

View File

@ -45,13 +45,13 @@ CREATE TABLE t1
children SMALLINT(2) NOT NULL
) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='people.csv'
HEADER=1 SEP_CHAR=';' QUOTED=1 READONLY=yes;
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
INSERT INTO t1 VALUES ('BILL','1973-06-30',5);
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
UPDATE t1 SET children=6 WHERE name='BILL';
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
DELETE FROM t1 WHERE name='BILL';
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
TRUNCATE TABLE t1;
SELECT * FROM t1;
ALTER TABLE t1 READONLY=no;
@ -60,7 +60,7 @@ INSERT INTO t1 VALUES ('BILL','1973-06-30',5);
SELECT * FROM t1;
ALTER TABLE t1 READONLY=1;
SHOW CREATE TABLE t1;
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
INSERT INTO t1 VALUES ('BILL','1973-06-30',5);
SELECT * FROM t1;
DROP TABLE t1;

View File

@ -66,13 +66,13 @@ INSERT INTO t1 VALUES (10),(20);
SELECT * FROM t1;
ALTER TABLE t1 READONLY=Yes;
SHOW CREATE TABLE t1;
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
INSERT INTO t1 VALUES (30);
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
UPDATE t1 SET a=30 WHERE a=10;
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
DELETE FROM t1 WHERE a=10;
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
TRUNCATE TABLE t1;
ALTER TABLE t1 READONLY=NO;
SHOW CREATE TABLE t1;

View File

@ -28,13 +28,13 @@ INSERT INTO t1 VALUES (10);
SELECT * FROM t1;
ALTER TABLE t1 READONLY=1;
SHOW CREATE TABLE t1;
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
INSERT INTO t1 VALUES (20);
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
UPDATE t1 SET id=20 WHERE id=10;
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
DELETE FROM t1 WHERE id=10;
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
TRUNCATE TABLE t1;
ALTER TABLE t1 READONLY=0;
SHOW CREATE TABLE t1;

View File

@ -99,13 +99,13 @@ INSERT INTO t1 VALUES ('UK',10),('FR',20),('RU',30);
SELECT * FROM t1;
ALTER TABLE t1 READONLY=1;
SHOW CREATE TABLE t1;
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
INSERT INTO t1 VALUES ('US',40);
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
UPDATE t1 SET c2=20 WHERE c2=10;
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
DELETE FROM t1 WHERE c2=10;
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
TRUNCATE TABLE t1;
ALTER TABLE t1 READONLY=0;
SHOW CREATE TABLE t1;

View File

@ -0,0 +1,27 @@
--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
CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/test/tx1';
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
connect (master,127.0.0.1,root,,test,$MASTER_MYPORT,);
connect (slave,127.0.0.1,root,,test,$SLAVE_MYPORT,);
connection master;
CREATE DATABASE connect;
connection slave;
CREATE DATABASE connect;

View File

@ -0,0 +1,9 @@
connection master;
--disable_warnings
DROP TABLE IF EXISTS connect.t1;
DROP DATABASE IF EXISTS connect;
connection slave;
DROP TABLE IF EXISTS connect.t1;
DROP DATABASE IF EXISTS connect;
--enable_warnings

View File

@ -0,0 +1,33 @@
-- source myconn.inc
connection slave;
CREATE TABLE t1 (
`id` int(20) primary key,
`group` int NOT NULL default 1,
`a\\b` int NOT NULL default 2,
`a\\` int unsigned,
`name` varchar(32) default 'name')
DEFAULT CHARSET=latin1;
connection master;
--replace_result $SLAVE_MYPORT SLAVE_PORT
eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/test/t1';
--replace_result $SLAVE_MYPORT SLAVE_PORT
SHOW CREATE TABLE t1;
INSERT INTO t1 (id, name) VALUES (1, 'foo');
INSERT INTO t1 (id, name) VALUES (2, 'fee');
--sorted_result
SELECT * FROM t1;
DROP TABLE t1;
connection slave;
--sorted_result
SELECT * FROM t1;
DROP TABLE t1;
-- source myconn_cleanup.inc

View File

@ -0,0 +1,45 @@
-- source myconn.inc
--echo #
--echo # Checking Sending Commands
--echo #
connection master;
--replace_result $SLAVE_MYPORT SLAVE_PORT
eval CREATE TABLE t1 (
command VARCHAR(128) NOT NULL,
warnings INT(4) NOT NULL FLAG=3,
number INT(5) NOT NULL FLAG=1,
message VARCHAR(255) FLAG=2)
ENGINE=CONNECT TABLE_TYPE=MYSQL CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/test' OPTION_LIST='Execsrc=1,maxerr=2';
SELECT * FROM t1 WHERE command IN ('Warning','Note',
'drop table if exists t1',
'create table t1 (id int key auto_increment, msg varchar(32) not null)',
"insert into t1(msg) values('One'),(NULL),('Three')",
"insert into t1 values(2,'Deux') on duplicate key update msg = 'Two'",
"insert into t1(message) values('Four'),('Five'),('Six')",
'insert into t1(id) values(NULL)',
"update t1 set msg = 'Four' where id = 4",
'select * from t1');
--echo #
--echo # Checking Using Procedure
--echo #
DROP PROCEDURE IF EXISTS p1;
CREATE PROCEDURE p1(cmd varchar(512))
READS SQL DATA
SELECT * FROM t1 WHERE command IN ('Warning','Note',cmd);
CALL p1('insert into t1(id) values(NULL)');
CALL p1('update t1 set msg = "Five" where id = 5');
DROP PROCEDURE p1;
DROP TABLE t1;
connection slave;
--sorted_result
SELECT * FROM t1;
DROP TABLE t1;
-- source myconn_cleanup.inc

View File

@ -0,0 +1,325 @@
-- source myconn.inc
#
# This test is run against a remote MySQL server
#
connection slave;
CREATE TABLE t1 (a int, b char(10));
INSERT INTO t1 VALUES (NULL,NULL),(0,'test00'),(1,'test01'),(2,'test02'),(3,'test03');
SELECT * FROM t1;
--echo #
--echo # Testing errors
--echo #
connection master;
# Bad user name
# Suppress "mysql_real_connect failed:" (printed in _DEBUG build)
--replace_result $SLAVE_MYPORT SLAVE_PORT "mysql_real_connect failed: " ""
--error ER_UNKNOWN_ERROR
eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
CONNECTION='mysql://unknown@127.0.0.1:$SLAVE_MYPORT/test/t1';
# Bad database name
--replace_result $SLAVE_MYPORT SLAVE_PORT "mysql_real_connect failed: " ""
--error ER_UNKNOWN_ERROR
eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/unknown/t1';
# Bad database name, with OPTION_LIST going first.
--replace_result $SLAVE_MYPORT SLAVE_PORT "mysql_real_connect failed: " ""
--error ER_UNKNOWN_ERROR
eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT' DBNAME='unknown' TABNAME='t1';
# Bad table name
--replace_result $SLAVE_MYPORT SLAVE_PORT
--error ER_UNKNOWN_ERROR
eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/test/unknown';
--error ER_NO_SUCH_TABLE
SHOW CREATE TABLE t1;
# Bad column name
--replace_result $SLAVE_MYPORT SLAVE_PORT
eval CREATE TABLE t1 (x int, y char(10)) ENGINE=CONNECT TABLE_TYPE=MYSQL
CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/test/t1';
--replace_result $SLAVE_MYPORT SLAVE_PORT
SHOW CREATE TABLE t1;
--error ER_GET_ERRMSG
SELECT * FROM t1;
DROP TABLE t1;
# The remote table disappeared
--replace_result $SLAVE_MYPORT SLAVE_PORT
eval CREATE TABLE t1 (a int, b char(10)) ENGINE=CONNECT TABLE_TYPE=MYSQL
CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/test/t1';
connection slave;
ALTER TABLE t1 RENAME t1backup;
connection master;
--error ER_GET_ERRMSG
SELECT * FROM t1;
connection slave;
ALTER TABLE t1backup RENAME t1;
connection master;
DROP TABLE t1;
--echo #
--echo # Testing SELECT, etc.
--echo #
# Automatic table structure
--replace_result $SLAVE_MYPORT SLAVE_PORT
eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/test/t1';
--replace_result $SLAVE_MYPORT SLAVE_PORT
SHOW CREATE TABLE t1;
SELECT * FROM t1;
DROP TABLE t1;
# Explicit table structure
--replace_result $SLAVE_MYPORT SLAVE_PORT
eval CREATE TABLE t1 (a int, b char(10)) ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1'
OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT';
--replace_result $SLAVE_MYPORT SLAVE_PORT
SHOW CREATE TABLE t1;
SELECT * FROM t1;
DROP TABLE t1;
# Explicit table structure: remote NULL, local NOT NULL
--replace_result $SLAVE_MYPORT SLAVE_PORT
eval CREATE TABLE t1 (a INT NOT NULL, b CHAR(10) NOT NULL) ENGINE=CONNECT TABLE_TYPE=MYSQL
OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT';
--replace_result $SLAVE_MYPORT SLAVE_PORT
SHOW CREATE TABLE t1;
SELECT * FROM t1;
DROP TABLE t1;
# Explicit table structure with wrong column types
--replace_result $SLAVE_MYPORT SLAVE_PORT
eval CREATE TABLE t1 (a char(10), b int) ENGINE=CONNECT TABLE_TYPE=MYSQL
CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/test/t1';
--replace_result $SLAVE_MYPORT SLAVE_PORT
SHOW CREATE TABLE t1;
SELECT * FROM t1;
DROP TABLE t1;
connection slave;
DROP TABLE t1;
--echo #
--echo # Testing numeric data types
--echo #
# TODO: mediumint is converted to int, float is converted to double, decimal is converted to double
CREATE TABLE t1 (a tinyint, b smallint, c mediumint, d int, e bigint, f float, g double, h decimal(20,5));
SHOW CREATE TABLE t1;
INSERT INTO t1 VALUES(100,3333,41235,1234567890,235000000000,3.14159265,3.14159265,3141.59265);
connection master;
--replace_result $SLAVE_MYPORT SLAVE_PORT
eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT';
--replace_result $SLAVE_MYPORT SLAVE_PORT
SHOW CREATE TABLE t1;
SELECT * FROM t1;
DROP TABLE t1;
connection slave;
DROP TABLE t1;
# TODO: unsigned does not work
#CREATE TABLE t1 (a tinyint unsigned);
#SHOW CREATE TABLE t1;
#connection master;
#--replace_result $SLAVE_MYPORT SLAVE_PORT
#eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT';
#--replace_result $SLAVE_MYPORT SLAVE_PORT
#SHOW CREATE TABLE t1;
#SELECT * FROM t1;
#DROP TABLE t1;
#connection slave;
#DROP TABLE t1;
# TODO: add test for BIT
--echo #
--echo # Testing character data types
--echo #
CREATE TABLE t1 (a char(12), b varchar(12));
SHOW CREATE TABLE t1;
INSERT INTO t1 VALUES('Welcome','Hello, World');
SELECT * FROM t1;
connection master;
--replace_result $SLAVE_MYPORT SLAVE_PORT
eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT';
--replace_result $SLAVE_MYPORT SLAVE_PORT
SHOW CREATE TABLE t1;
SELECT * FROM t1;
DROP TABLE t1;
connection slave;
DROP TABLE t1;
# TODO: ERROR 1105: Unsupported column type tinytext
#CREATE TABLE t1 (a tinytext);
#--replace_result $SLAVE_MYPORT SLAVE_PORT
#eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT'
#--replace_result $SLAVE_MYPORT SLAVE_PORT
#SHOW CREATE TABLE t1;
#--replace_result $SLAVE_MYPORT SLAVE_PORT
#SHOW CREATE TABLE t1;
#SELECT * FROM t1;
#DROP TABLE t1, t1;
# TODO: ERROR 1105: Unsupported column type mediumtext
#CREATE TABLE t1 (a mediumtext);
#--replace_result $SLAVE_MYPORT SLAVE_PORT
#eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT'
#--replace_result $SLAVE_MYPORT SLAVE_PORT
#SHOW CREATE TABLE t1;
#--replace_result $SLAVE_MYPORT SLAVE_PORT
#SHOW CREATE TABLE t1;
#SELECT * FROM t1;
#DROP TABLE t1, t1;
# TODO: text is converted to varchar(256)
#CREATE TABLE t1 (a text);
#--replace_result $SLAVE_MYPORT SLAVE_PORT
#eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT'
#--replace_result $SLAVE_MYPORT SLAVE_PORT
#SHOW CREATE TABLE t1;
#--replace_result $SLAVE_MYPORT SLAVE_PORT
#SHOW CREATE TABLE t1;
#SELECT * FROM t1;
#DROP TABLE t1, t1;
# TODO: ERROR 1105: Unsupported column type longtext
#CREATE TABLE t1 (a longtext);
#--replace_result $SLAVE_MYPORT SLAVE_PORT
#eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT'
#--replace_result $SLAVE_MYPORT SLAVE_PORT
#SHOW CREATE TABLE t1;
#--replace_result $SLAVE_MYPORT SLAVE_PORT
#SHOW CREATE TABLE t1;
#SELECT * FROM t1;
#DROP TABLE t1, t1;
#TODO: add tests for ENUM
#TODO: add tests for SET
#--echo #
#--echo # Testing binary data types
#--echo #
# TODO: ERROR 1105: Unsupported column type binary
#CREATE TABLE t1 (a binary(10));
#--replace_result $SLAVE_MYPORT SLAVE_PORT
#eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT'
#--replace_result $SLAVE_MYPORT SLAVE_PORT
#SHOW CREATE TABLE t1;
#--replace_result $SLAVE_MYPORT SLAVE_PORT
#SHOW CREATE TABLE t1;
#SELECT * FROM t1;
#DROP TABLE t1, t1;
# TODO: ERROR 1105: Unsupported column type varbinary
#CREATE TABLE t1 (a varbinary(10));
#--replace_result $SLAVE_MYPORT SLAVE_PORT
#eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT'
#--replace_result $SLAVE_MYPORT SLAVE_PORT
#SHOW CREATE TABLE t1;
#--replace_result $SLAVE_MYPORT SLAVE_PORT
#SHOW CREATE TABLE t1;
#SELECT * FROM t1;
#DROP TABLE t1, t1;
# TODO: ERROR 1105: Unsupported column type tinyblob
#CREATE TABLE t1 (a tinyblob);
#--replace_result $SLAVE_MYPORT SLAVE_PORT
#eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT'
#--replace_result $SLAVE_MYPORT SLAVE_PORT
#SHOW CREATE TABLE t1;
#--replace_result $SLAVE_MYPORT SLAVE_PORT
#SHOW CREATE TABLE t1;
#SELECT * FROM t1;
#DROP TABLE t1, t1;
# TODO: ERROR 1105: Unsupported column type mediumblob
#CREATE TABLE t1 (a mediumblob);
#--replace_result $SLAVE_MYPORT SLAVE_PORT
#eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT'
#--replace_result $SLAVE_MYPORT SLAVE_PORT
#SHOW CREATE TABLE t1;
#--replace_result $SLAVE_MYPORT SLAVE_PORT
#SHOW CREATE TABLE t1;
#SELECT * FROM t1;
#DROP TABLE t1, t1;
# TODO: blob is converted to varchar(256)
#CREATE TABLE t1 (a blob);
#--replace_result $SLAVE_MYPORT SLAVE_PORT
#eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT'
#--replace_result $SLAVE_MYPORT SLAVE_PORT
#SHOW CREATE TABLE t1;
#--replace_result $SLAVE_MYPORT SLAVE_PORT
#SHOW CREATE TABLE t1;
#SELECT * FROM t1;
#DROP TABLE t1, t1;
# TODO: ERROR 1105: Unsupported column type longblob
#CREATE TABLE t1 (a longblob);
#--replace_result $SLAVE_MYPORT SLAVE_PORT
#eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT'
#--replace_result $SLAVE_MYPORT SLAVE_PORT
#SHOW CREATE TABLE t1;
#--replace_result $SLAVE_MYPORT SLAVE_PORT
#SHOW CREATE TABLE t1;
#SELECT * FROM t1;
#DROP TABLE t1, t1;
# TODO: ERROR 1105: Unsupported column type geometry
#CREATE TABLE t1 (a geometry);
#--replace_result $SLAVE_MYPORT SLAVE_PORT
#eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT'
#--replace_result $SLAVE_MYPORT SLAVE_PORT
#SHOW CREATE TABLE t1;
#--replace_result $SLAVE_MYPORT SLAVE_PORT
#SHOW CREATE TABLE t1;
#SELECT * FROM t1;
#DROP TABLE t1, t1;
--echo #
--echo # Testing temporal data types
--echo #
CREATE TABLE t1 (a date, b datetime, c time, d timestamp, e year);
SHOW CREATE TABLE t1;
INSERT INTO t1 VALUES('2003-05-27 10:45:23','2003-05-27 10:45:23','2003-05-27 10:45:23','2003-05-27 10:45:23','2003-05-27 10:45:23');
SELECT * FROM t1;
connection master;
--replace_result $SLAVE_MYPORT SLAVE_PORT
eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT';
--replace_result $SLAVE_MYPORT SLAVE_PORT
SHOW CREATE TABLE t1;
SELECT * FROM t1;
DROP TABLE t1;
connection slave;
DROP TABLE t1;
-- source myconn_cleanup.inc

View File

@ -67,3 +67,13 @@ SELECT * FROM v1;
DROP VIEW v1;
DROP TABLE t1;
--replace_result $MTR_SUITE_DIR MTR_SUITE_DIR
--eval CREATE TABLE t1 ENGINE=CONNECT CATFUNC=Columns TABNAME='t1' TABLE_TYPE=ODBC CONNECTION='Driver=SQLite3 ODBC Driver;Database=$Database;NoWCHAR=yes' CHARSET=utf8 DATA_CHARSET=utf8
SELECT * FROM t1;
DROP TABLE t1;
--replace_result $MTR_SUITE_DIR MTR_SUITE_DIR
--eval CREATE TABLE t1 ENGINE=CONNECT CATFUNC=Tables TABNAME='t1' TABLE_TYPE=ODBC CONNECTION='Driver=SQLite3 ODBC Driver;Database=$Database;NoWCHAR=yes' CHARSET=utf8 DATA_CHARSET=utf8
SELECT * FROM t1;
DROP TABLE t1;

View File

@ -23,4 +23,17 @@ let $MYSQLD_DATADIR= `select @@datadir`;
SELECT Nom, Fonction FROM contact WHERE Repertoire='ascii';
DROP TABLE contact;
--replace_result $MYSQLD_DATADIR DATADIR
--eval CREATE TABLE t1 ENGINE=CONNECT CATFUNC=Tables TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineXLS;DBQ=$MYSQLD_DATADIR/test/contacts.xls' CHARSET=utf8 DATA_CHARSET=latin1;
--replace_result $MYSQLD_DATADIR DATADIR
SELECT * FROM t1 WHERE Table_name='CONTACT';
DROP TABLE t1;
--replace_result $MYSQLD_DATADIR DATADIR
--eval CREATE TABLE t1 ENGINE=CONNECT CATFUNC=Columns TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineXLS;DBQ=$MYSQLD_DATADIR/test/contacts.xls' CHARSET=utf8 DATA_CHARSET=latin1;
--replace_result $MYSQLD_DATADIR DATADIR
SELECT * FROM t1 WHERE Table_name='CONTACT' AND Column_name IN ('Nom','Fonction');
DROP TABLE t1;
--remove_file $MYSQLD_DATADIR/test/contacts.xls

View File

@ -52,13 +52,13 @@ SELECT fname, ftype, size FROM dir1 ORDER BY fname, ftype;
--echo #
ALTER TABLE t1 READONLY=yes;
SHOW CREATE TABLE t1;
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
INSERT INTO t1 VALUES (4,'test04');
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
UPDATE t1 SET b='test04' WHERE a=3;
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
DELETE FROM t1 WHERE a=3;
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
TRUNCATE TABLE t1;
ALTER TABLE t1 READONLY=no;
SHOW CREATE TABLE t1;

View File

@ -29,7 +29,7 @@
/************************************************************************/
/* Convert from MySQL type name to PlugDB type number */
/************************************************************************/
int MYSQLtoPLG(char *typname)
int MYSQLtoPLG(char *typname, char *var)
{
int type;
@ -56,6 +56,28 @@ int MYSQLtoPLG(char *typname)
else
type = TYPE_ERROR;
if (var) {
// This is to make the difference between CHAR and VARCHAR
if (type == TYPE_STRING && stricmp(typname, "char"))
*var = 'V';
// This is to make the difference between temporal values
if (type == TYPE_DATE) {
if (!stricmp(typname, "date"))
*var = 'D';
else if (!stricmp(typname, "datetime"))
*var = 'A';
else if (!stricmp(typname, "timestamp"))
*var = 'S';
else if (!stricmp(typname, "time"))
*var = 'T';
else if (!stricmp(typname, "year"))
*var = 'Y';
} // endif type
} // endif var
return type;
} // end of MYSQLtoPLG
@ -98,14 +120,18 @@ enum enum_field_types PLGtoMYSQL(int type, bool dbf)
/************************************************************************/
/* Convert from PlugDB type to MySQL type name */
/************************************************************************/
const char *PLGtoMYSQLtype(int type, bool dbf)
const char *PLGtoMYSQLtype(int type, bool dbf, char v)
{
switch (type) {
case TYPE_INT: return "INT";
case TYPE_SHORT: return "SMALLINT";
case TYPE_FLOAT: return "DOUBLE";
case TYPE_DATE: return dbf ? "DATE" : "DATETIME";
case TYPE_STRING: return "VARCHAR";
case TYPE_DATE: return dbf ? "DATE" :
(v == 'S') ? "TIMESTAMP" :
(v == 'D') ? "DATE" :
(v == 'T') ? "TIME" :
(v == 'Y') ? "YEAR" : "DATETIME";
case TYPE_STRING: return v ? "VARCHAR" : "CHAR";
case TYPE_BIGINT: return "BIGINT";
case TYPE_TINY: return "TINYINT";
default: return "CHAR(0)";

View File

@ -1,9 +1,14 @@
/***********************************************************************/
/* Prototypes of Functions used externally. */
/***********************************************************************/
#ifndef __MYUTIL__H
#define __MYUTIL__H
enum enum_field_types PLGtoMYSQL(int type, bool dbf);
const char *PLGtoMYSQLtype(int type, bool dbf);
int MYSQLtoPLG(char *typname);
const char *PLGtoMYSQLtype(int type, bool dbf, char var = NULL);
int MYSQLtoPLG(char *typname, char *var = NULL);
int MYSQLtoPLG(int mytype);
char *MyDateFmt(int mytype);
char *MyDateFmt(char *typname);
#endif // __MYUTIL__H

View File

@ -1,7 +1,9 @@
/***********************************************************************/
/* ODBC catalog function prototypes. */
/***********************************************************************/
#if defined(PROMPT_OK)
char *ODBCCheckConnection(PGLOBAL g, char *dsn, int cop);
#endif // PROMPT_OK
PQRYRES ODBCDataSources(PGLOBAL g, bool info);
PQRYRES ODBCColumns(PGLOBAL g, char *dsn, char *table,
char *colpat, bool info);

View File

@ -108,16 +108,18 @@ static int GetSQLCType(int type)
/***********************************************************************/
/* TranslateSQLType: translate a SQL Type to a PLG type. */
/***********************************************************************/
int TranslateSQLType(int stp, int prec, int& len)
int TranslateSQLType(int stp, int prec, int& len, char& v)
{
int type;
switch (stp) {
case SQL_CHAR: // 1
case SQL_VARCHAR: // 12
v = 'V';
case SQL_CHAR: // 1
type = TYPE_STRING;
break;
case SQL_LONGVARCHAR: // (-1)
v = 'V';
type = TYPE_STRING;
len = min(abs(len), 255);
break;
@ -172,6 +174,7 @@ int TranslateSQLType(int stp, int prec, int& len)
return type;
} // end of TranslateSQLType
#if defined(PROMPT_OK)
/***********************************************************************/
/* ODBCCheckConnection: Check completeness of connection string. */
/***********************************************************************/
@ -203,6 +206,7 @@ char *ODBCCheckConnection(PGLOBAL g, char *dsn, int cop)
ocp->Close();
return newdsn; // Return complete connection string
} // end of ODBCCheckConnection
#endif // PROMPT_OK
/***********************************************************************/
/* Allocate the structure used to refer to the result set. */
@ -871,7 +875,8 @@ ODBConn::ODBConn(PGLOBAL g, TDBODBC *tdbp)
m_Connect = NULL;
m_Updatable = true;
m_Transact = false;
m_IDQuoteChar = '\'';
m_IDQuoteChar[0] = '"';
m_IDQuoteChar[1] = 0;
//*m_ErrMsg = '\0';
} // end of ODBConn
@ -889,7 +894,7 @@ bool ODBConn::Check(RETCODE rc)
{
switch (rc) {
case SQL_SUCCESS_WITH_INFO:
if (trace > 1) {
if (trace) {
DBX x(rc);
x.BuildErrorMessage(this, m_hstmt);
@ -1113,7 +1118,7 @@ bool ODBConn::Connect(DWORD Options)
if (hWnd == NULL)
hWnd = GetDesktopWindow();
#else // !WIN32
HWND hWnd = 1;
HWND hWnd = (HWND)1;
#endif // !WIN32
PGLOBAL& g = m_G;
PDBUSER dup = PlgGetUser(g);
@ -1230,20 +1235,13 @@ void ODBConn::GetConnectInfo()
SQL_MODE_READ_ONLY);
#endif // 0
// Cache the quote char to use when constructing SQL
char QuoteChar[2];
// Get the quote char to use when constructing SQL
rc = SQLGetInfo(m_hdbc, SQL_IDENTIFIER_QUOTE_CHAR,
QuoteChar, sizeof(QuoteChar), &nResult);
if (Check(rc) && nResult == 1)
m_IDQuoteChar = QuoteChar[0];
else
m_IDQuoteChar = ' ';
m_IDQuoteChar, sizeof(m_IDQuoteChar), &nResult);
if (trace)
htrc("DBMS: %s, Version: %s",
GetStringInfo(SQL_DBMS_NAME), GetStringInfo(SQL_DBMS_VER));
htrc("DBMS: %s, Version: %s, rc=%d\n",
GetStringInfo(SQL_DBMS_NAME), GetStringInfo(SQL_DBMS_VER), rc);
} // end of GetConnectInfo
@ -1511,14 +1509,16 @@ int ODBConn::PrepareSQL(char *sql)
hstmt = m_hstmt;
m_hstmt = NULL;
ThrowDBX(MSG(SEQUENCE_ERROR));
} else {
rc = SQLAllocStmt(m_hdbc, &hstmt);
if (!Check(rc))
ThrowDBX(SQL_INVALID_HANDLE, "SQLAllocStmt");
if (m_Tdb->GetAmType() != TYPE_AM_XDBC)
ThrowDBX(MSG(SEQUENCE_ERROR));
} // endif hstmt
} // endif m_hstmt
rc = SQLAllocStmt(m_hdbc, &hstmt);
if (!Check(rc))
ThrowDBX(SQL_INVALID_HANDLE, "SQLAllocStmt");
OnSetOptions(hstmt);
b = true;
@ -1565,7 +1565,7 @@ int ODBConn::PrepareSQL(char *sql)
/***********************************************************************/
/* Execute a prepared statement. */
/***********************************************************************/
int ODBConn::ExecuteSQL(bool x)
int ODBConn::ExecuteSQL(void)
{
PGLOBAL& g = m_G;
SWORD ncol = 0;
@ -1580,26 +1580,17 @@ int ODBConn::ExecuteSQL(bool x)
if (!Check(rc))
ThrowDBX(rc, "SQLExecute", m_hstmt);
if (!Check(SQLNumResultCols(m_hstmt, &ncol)))
if (!Check(rc = 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
// This should never happen while inserting
strcpy(g->Message, "Logical error while inserting");
} else {
// Insert, Update or Delete statement
if (!Check(SQLRowCount(m_hstmt, &afrw)))
if (!Check(rc = SQLRowCount(m_hstmt, &afrw)))
ThrowDBX(rc, "SQLRowCount", m_hstmt);
if (x)
strcpy(g->Message, "Affected rows");
} // endif ncol
} catch(DBX *x) {
@ -1613,6 +1604,7 @@ int ODBConn::ExecuteSQL(bool x)
m_Transact = false;
} // endif m_Transact
afrw = -1;
} // end try/catch
return (int)afrw;
@ -1667,6 +1659,112 @@ bool ODBConn::BindParam(ODBCCOL *colp)
return false;
} // end of BindParam
/***********************************************************************/
/* Execute an SQL command. */
/***********************************************************************/
bool ODBConn::ExecSQLcommand(char *sql)
{
char cmd[16];
bool b, rcd = false;
UINT txn = 0;
PGLOBAL& g = m_G;
SWORD ncol = 0;
SQLLEN afrw;
RETCODE rc;
HSTMT hstmt;
try {
b = FALSE;
// Check whether we should use transaction
if (sscanf(sql, " %15s ", cmd) == 1) {
if (!stricmp(cmd, "INSERT") || !stricmp(cmd, "UPDATE") ||
!stricmp(cmd, "DELETE") || !stricmp(cmd, "REPLACE")) {
// Does the data source support transactions
rc = SQLGetInfo(m_hdbc, SQL_TXN_CAPABLE, &txn, 0, NULL);
if (Check(rc) && txn != SQL_TC_NONE) {
rc = SQLSetConnectAttr(m_hdbc, SQL_ATTR_AUTOCOMMIT,
SQL_AUTOCOMMIT_OFF, SQL_IS_UINTEGER);
if (!Check(rc))
ThrowDBX(SQL_INVALID_HANDLE, "SQLSetConnectAttr");
m_Transact = TRUE;
} // endif txn
} // endif cmd
} // endif sql
// Allocate the statement handle
rc = SQLAllocStmt(m_hdbc, &hstmt);
if (!Check(rc))
ThrowDBX(SQL_INVALID_HANDLE, "SQLAllocStmt");
OnSetOptions(hstmt);
b = true;
if (trace)
htrc("ExecSQLcommand hstmt=%p %.64s\n", hstmt, sql);
// Proceed with command execution
do {
rc = SQLExecDirect(hstmt, (PUCHAR)sql, SQL_NTS);
} while (rc == SQL_STILL_EXECUTING);
if (!Check(rc))
ThrowDBX(rc, "SQLExecDirect", hstmt);
// Check whether this is a query returning a result set
if (!Check(rc = SQLNumResultCols(hstmt, &ncol)))
ThrowDBX(rc, "SQLNumResultCols", hstmt);
if (!ncol) {
if (!Check(SQLRowCount(hstmt, &afrw)))
ThrowDBX(rc, "SQLRowCount", hstmt);
m_Tdb->AftRows = (int)afrw;
strcpy(g->Message, "Affected rows");
} else {
m_Tdb->AftRows = (int)ncol;
strcpy(g->Message, "Result set column number");
} // endif ncol
} catch(DBX *x) {
if (trace)
for (int i = 0; i < MAX_NUM_OF_MSG && x->m_ErrMsg[i]; i++)
htrc(x->m_ErrMsg[i]);
sprintf(g->Message, "Remote: %s", x->GetErrorMessage(0));
if (b)
SQLCancel(hstmt);
m_Tdb->AftRows = -1;
rcd = true;
} // end try/catch
if (!Check(rc = SQLFreeStmt(hstmt, SQL_CLOSE)))
sprintf(g->Message, "SQLFreeStmt: rc=%d", rc);
if (m_Transact) {
// Terminate the transaction
if (!Check(rc = SQLEndTran(SQL_HANDLE_DBC, m_hdbc,
(rcd) ? SQL_ROLLBACK : SQL_COMMIT)))
sprintf(g->Message, "SQLEndTran: rc=%d", rc);
if (!Check(rc = SQLSetConnectAttr(m_hdbc, SQL_ATTR_AUTOCOMMIT,
(SQLPOINTER)SQL_AUTOCOMMIT_ON, SQL_IS_UINTEGER)))
sprintf(g->Message, "SQLSetConnectAttr: rc=%d", rc);
m_Transact = false;
} // endif m_Transact
return rcd;
} // end of ExecSQLcommand
/**************************************************************************/
/* GetMetaData: constructs the result blocks containing the */
/* description of all the columns of an SQL command. */

View File

@ -127,7 +127,7 @@ class ODBConn : public BLOCK {
// Attributes
public:
char GetQuoteChar(void) {return m_IDQuoteChar;}
char *GetQuoteChar(void) {return m_IDQuoteChar;}
// Database successfully opened?
bool IsOpen(void) {return m_hdbc != SQL_NULL_HDBC;}
PSZ GetStringInfo(ushort infotype);
@ -142,8 +142,9 @@ class ODBConn : public BLOCK {
int ExecDirectSQL(char *sql, ODBCCOL *tocols);
int Fetch(void);
int PrepareSQL(char *sql);
int ExecuteSQL(bool x);
int ExecuteSQL(void);
bool BindParam(ODBCCOL *colp);
bool ExecSQLcommand(char *sql);
int GetCatInfo(CATPARM *cap);
bool GetDataSources(PQRYRES qrp);
bool GetDrivers(PQRYRES qrp);
@ -183,9 +184,9 @@ class ODBConn : public BLOCK {
DWORD m_QueryTimeout;
DWORD m_UpdateOptions;
DWORD m_RowsetSize;
char m_IDQuoteChar[2];
int m_Catver;
PSZ m_Connect;
bool m_Updatable;
bool m_Transact;
char m_IDQuoteChar;
}; // end of ODBConn class definition

View File

@ -106,13 +106,20 @@ enum AMT {TYPE_AM_ERROR = 0, /* Type not defined */
TYPE_AM_DOM = 80, /* DOM access method type no */
TYPE_AM_DIR = 90, /* DIR access method type no */
TYPE_AM_ODBC = 100, /* ODBC access method type no */
TYPE_AM_XDBC = 101, /* XDBC access method type no */
TYPE_AM_OEM = 110, /* OEM access method type no */
TYPE_AM_TBL = 115, /* TBL access method type no */
TYPE_AM_PIVOT = 120, /* PIVOT access method type no */
TYPE_AM_SRC = 121, /* PIVOT multiple column type no */
TYPE_AM_FNC = 122, /* PIVOT source column type no */
TYPE_AM_XCOL = 124, /* XCOL access method type no */
TYPE_AM_XML = 127, /* XML access method type no */
TYPE_AM_OCCUR = 128, /* OCCUR access method type no */
TYPE_AM_PRX = 129, /* PROXY access method type no */
TYPE_AM_XTB = 130, /* SYS table access method type */
TYPE_AM_BLK = 131, /* BLK access method type no */
TYPE_AM_ZIP = 132, /* ZIP access method type no */
TYPE_AM_ZLIB = 133, /* ZLIB access method type no */
TYPE_AM_MAC = 137, /* MAC table access method type */
TYPE_AM_WMI = 139, /* WMI table access method type */
TYPE_AM_XCL = 140, /* SYS column access method type */
@ -123,7 +130,8 @@ enum AMT {TYPE_AM_ERROR = 0, /* Type not defined */
TYPE_AM_DMY = 172, /* DMY Dummy tables am type no */
TYPE_AM_SET = 180, /* SET Set tables am type no */
TYPE_AM_MYSQL = 192, /* MYSQL access method type no */
TYPE_AM_CAT = 193, /* Catalog access method type no */
TYPE_AM_MYX = 193, /* MYSQL EXEC access method type */
TYPE_AM_CAT = 195, /* Catalog access method type no */
TYPE_AM_OUT = 200}; /* Output relations (storage) */
enum RECFM {RECFM_NAF = -2, /* Not a file */
@ -585,4 +593,4 @@ 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);
bool PushWarning(PGLOBAL, PTDBASE, int level = 1);

View File

@ -330,7 +330,7 @@ PQRYRES PlgAllocResult(PGLOBAL g, int ncol, int maxres, int ids,
// Allocate the Value Block that will contain data
if (crp->Length || nonull)
crp->Kdata = AllocValBlock(g, NULL, crp->Type, maxres,
crp->Length, 0, true, blank);
crp->Length, 0, true, blank, false);
else
crp->Kdata = NULL;

View File

@ -77,7 +77,7 @@ extern "C" int trace;
/* No conversion of block values (check = true). */
/***********************************************************************/
PVBLK AllocValBlock(PGLOBAL, void *, int, int, int len = 0, int prec = 0,
bool check = true, bool blank = false);
bool check = true, bool blank = false, bool un = false);
/* --------------------------- Class DOSDEF -------------------------- */

View File

@ -524,6 +524,7 @@ bool TDBCAT::OpenDB(PGLOBAL g)
if (Initialize(g))
return true;
Use = USE_OPEN;
return InitCol(g);
} // end of OpenDB

View File

@ -321,7 +321,7 @@ bool MYSQLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
Portnumber = Cat->GetIntCatInfo("Port", GetDefaultPort());
Server = Hostname;
} else if (ParseURL(g, url))
return TRUE;
return true;
Bind = !!Cat->GetIntCatInfo("Bind", 0);
Delayed = !!Cat->GetIntCatInfo("Delayed", 0);
@ -344,7 +344,7 @@ bool MYSQLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
char *locdb = Database;
if (ParseURL(g, url))
return TRUE;
return true;
Database = locdb;
} // endif url
@ -353,9 +353,15 @@ bool MYSQLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
} // endif am
if ((Srcdef = Cat->GetStringCatInfo(g, "Srcdef", NULL)))
Isview = TRUE;
Isview = true;
Xsrc = Cat->GetBoolCatInfo("Execsrc", FALSE);
// Used for Update and Delete
Qrystr = Cat->GetStringCatInfo(g, "Query_String", "?");
Quoted = Cat->GetIntCatInfo("Quoted", 0);
// Specific for command executing tables
Xsrc = Cat->GetBoolCatInfo("Execsrc", false);
Mxr = Cat->GetIntCatInfo("Maxerr", 0);
return FALSE;
} // end of DefineAM
@ -388,6 +394,8 @@ TDBMYSQL::TDBMYSQL(PMYDEF tdp) : TDBASE(tdp)
User = tdp->Username;
Pwd = tdp->Password;
Server = tdp->Server;
Qrystr = tdp->Qrystr;
Quoted = max(0, tdp->Quoted);
Port = tdp->Portnumber;
Isview = tdp->Isview;
Prep = tdp->Bind;
@ -400,6 +408,8 @@ TDBMYSQL::TDBMYSQL(PMYDEF tdp) : TDBASE(tdp)
User = NULL;
Pwd = NULL;
Server = NULL;
Qrystr = NULL;
Quoted = 0;
Port = 0;
Isview = FALSE;
Prep = FALSE;
@ -424,6 +434,8 @@ TDBMYSQL::TDBMYSQL(PGLOBAL g, PTDBMY tdbp) : TDBASE(tdbp)
Srcdef = tdbp->Srcdef;
User = tdbp->User;
Pwd = tdbp->Pwd;
Qrystr = tdbp->Qrystr;
Quoted = tdbp->Quoted;
Port = tdbp->Port;
Isview = tdbp->Isview;
Prep = tdbp->Prep;
@ -516,7 +528,7 @@ bool TDBMYSQL::MakeSelect(PGLOBAL g)
strcat(strcat(strcat(strcat(Query, " FROM "), tk), Tabname), tk);
if (To_Filter)
strcat(strcat(Query, " WHERE "), To_Filter);
strcat(strcat(Query, " WHERE "), To_Filter->Body);
if (trace)
htrc("Query=%s\n", Query);
@ -610,118 +622,109 @@ bool TDBMYSQL::MakeInsert(PGLOBAL g)
return FALSE;
} // end of MakeInsert
/***********************************************************************/
/* MakeCommand: make the Update or Delete statement to send to the */
/* MySQL server. Limited to remote values and filtering. */
/***********************************************************************/
int TDBMYSQL::MakeCommand(PGLOBAL g)
{
Query = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 64);
if (Quoted > 0 || stricmp(Name, Tabname)) {
char *p, *qrystr, name[68];
bool qtd = Quoted > 0;
// Make a lower case copy of the originale query
qrystr = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 1);
strlwr(strcpy(qrystr, Qrystr));
// Check whether the table name is equal to a keyword
// If so, it must be quoted in the original query
strlwr(strcat(strcat(strcpy(name, "`"), Name), "`"));
if (!strstr("`update`delete`low_priority`ignore`quick`from`", name))
strlwr(strcpy(name, Name)); // Not a keyword
if ((p = strstr(qrystr, name))) {
memcpy(Query, Qrystr, p - qrystr);
Query[p - qrystr] = 0;
if (qtd && *(p-1) == ' ')
strcat(strcat(strcat(Query, "`"), Tabname), "`");
else
strcat(Query, Tabname);
strcat(Query, Qrystr + (p - qrystr) + strlen(name));
} else {
sprintf(g->Message, "Cannot use this %s command",
(Mode == MODE_UPDATE) ? "UPDATE" : "DELETE");
return RC_FX;
} // endif p
} else
strcpy(Query, Qrystr);
return RC_OK;
} // end of MakeCommand
#if 0
/***********************************************************************/
/* MakeUpdate: make the Update statement use with MySQL connection. */
/* Note: currently limited to local values and filtering. */
/* Limited to remote values and filtering. */
/***********************************************************************/
bool TDBMYSQL::MakeUpdate(PGLOBAL g, PSELECT selist)
int TDBMYSQL::MakeUpdate(PGLOBAL g)
{
char *setlist, *colname, *where = NULL, *tk = "`";
int len = 0, nset = 0;
bool b = FALSE;
PXOB xp;
PSELECT selp;
char *qc, cmd[8], tab[96], end[1024];
if (Query)
return FALSE; // already done
Query = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 64);
memset(end, 0, sizeof(end));
if (To_Filter)
if (To_Filter->CheckLocal(this)) {
where = (char*)PlugSubAlloc(g, NULL, 512); // Should be enough
*where = '\0';
if (sscanf(Qrystr, "%s `%[^`]`%1023c", cmd, tab, end) > 2 ||
sscanf(Qrystr, "%s \"%[^\"]\"%1023c", cmd, tab, end) > 2)
qc = "`";
else if (sscanf(Qrystr, "%s %s%1023c", cmd, tab, end) > 2
&& !stricmp(tab, Name))
qc = (Quoted) ? "`" : "";
else {
strcpy(g->Message, "Cannot use this UPDATE command");
return RC_FX;
} // endif sscanf
if (!PlugRephraseSQL(g, where, To_Filter, TYPE_FILTER, tk))
return TRUE;
To_Filter = NULL;
len = strlen(where);
} else {
strcpy(g->Message, MSG(NO_REF_UPDATE));
return TRUE;
} // endif Local
for (selp = selist; selp; selp = selp->GetNext_Proj())
nset++;
assert(nset);
// Allocate a pretty big buffer
setlist = (char*)PlugSubAlloc(g, NULL, 256 * nset);
*setlist = '\0';
for (selp = selist; selp; selp = selp->GetNext_Proj()) {
if (selp->GetSetType() == TYPE_COLBLK) {
colname = selp->GetSetCol()->GetName();
} else if (selp->GetSetType() == TYPE_COLUMN) {
colname = (char*)((PCOLUMN)selp->GetSetCol())->GetName();
} else {
sprintf(g->Message, MSG(BAD_SET_TYPE), selp->GetSetType());
return TRUE;
} // endif Type
if (b)
strcat(setlist, ", ");
else
b = TRUE;
strcat(strcat(strcat(strcat(setlist, tk), colname), tk), " = ");
xp = selp->GetObject();
if (!xp->CheckLocal(this)) {
strcpy(g->Message, MSG(NO_REF_UPDATE));
return TRUE;
} else if (xp->GetType() == TYPE_SUBQ)
// Cannot be correlated because CheckLocal would have failed
xp = new(g) CONSTANT(xp->GetValue());
if (!PlugRephraseSQL(g, setlist + strlen(setlist),
xp, TYPE_XOBJECT, tk))
return TRUE;
} // endfor selp
// Below 16 is enough to take care of the fixed part of the query
len += (strlen(setlist) + strlen(Tabname) + 16);
Query = (char*)PlugSubAlloc(g, NULL, len);
strcat(strcat(strcat(strcpy(Query, "UPDATE "), tk), Tabname), tk);
strcat(strcat(Query, " SET "), setlist);
if (where)
strcat(Query, where);
return FALSE;
assert(!stricmp(cmd, "update"));
strcat(strcat(strcat(strcpy(Query, "UPDATE "), qc), Tabname), qc);
strcat(Query, end);
return RC_OK;
} // end of MakeUpdate
/***********************************************************************/
/* MakeDelete: make the Delete statement use with MySQL connection. */
/* If no filtering Truncate is used because it is faster than Delete. */
/* However, the number of deleted lines is not returned by MySQL. */
/* Note: currently limited to local filtering. */
/* MakeDelete: make the Delete statement used with MySQL connection. */
/* Limited to remote filtering. */
/***********************************************************************/
bool TDBMYSQL::MakeDelete(PGLOBAL g)
int TDBMYSQL::MakeDelete(PGLOBAL g)
{
char *tk = "`";
int len = 0;
char *qc, cmd[8], from[8], tab[96], end[512];
if (Query)
return FALSE; // already done
Query = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 64);
memset(end, 0, sizeof(end));
if (!To_Filter)
AftRows = -1; // Means "all lines deleted"
if (sscanf(Qrystr, "%s %s `%[^`]`%511c", cmd, from, tab, end) > 2 ||
sscanf(Qrystr, "%s %s \"%[^\"]\"%511c", cmd, from, tab, end) > 2)
qc = "`";
else if (sscanf(Qrystr, "%s %s %s%511c", cmd, from, tab, end) > 2)
qc = (Quoted) ? "`" : "";
else {
strcpy(g->Message, "Cannot use this DELETE command");
return RC_FX;
} // endif sscanf
// Below 16 is more than length of 'delete from ' + 3
len += (strlen(Tabname) + 16);
len += (To_Filter ? strlen(To_Filter) + 7 : 0);
Query = (char*)PlugSubAlloc(g, NULL, len);
strcpy(Query, (To_Filter) ? "DELETE FROM " : "TRUNCATE ");
strcat(strcat(strcat(Query, tk), Tabname), tk);
assert(!stricmp(cmd, "delete") && !stricmp(from, "from"));
strcat(strcat(strcat(strcpy(Query, "DELETE FROM "), qc), Tabname), qc);
if (To_Filter)
strcat(strcat(Query, " WHERE "), To_Filter);
if (*end)
strcat(Query, end);
return FALSE;
return RC_OK;
} // end of MakeDelete
#endif // 0
@ -751,7 +754,8 @@ int TDBMYSQL::GetMaxSize(PGLOBAL g)
Query = NULL; // Must be remade when columns are known
#endif // 0
MaxSize = 10; // To make MySQL happy
// Return 0 in mode DELETE in case of delete all.
MaxSize = (Mode == MODE_DELETE) ? 0 : 10; // To make MySQL happy
} // endif MaxSize
return MaxSize;
@ -766,12 +770,11 @@ int TDBMYSQL::RowNumber(PGLOBAL g, bool b)
} // end of RowNumber
/***********************************************************************/
/* Return 0 in mode DELETE to tell that the delete is done. */
/* Return 0 in mode UPDATE to tell that the update is done. */
/***********************************************************************/
int TDBMYSQL::GetProgMax(PGLOBAL g)
{
return (Mode == MODE_DELETE || Mode == MODE_UPDATE) ? 0
: GetMaxSize(g);
return (Mode == MODE_UPDATE) ? 0 : GetMaxSize(g);
} // end of GetProgMax
/***********************************************************************/
@ -874,33 +877,17 @@ bool TDBMYSQL::OpenDB(PGLOBAL g)
m_Rc = Myc.ExecSQL(g, cmd, &w);
} // endif m_Rc
#if 0
} else if (Next) {
strcpy(g->Message, MSG(NO_JOIN_UPDEL));
} else if (Mode == MODE_DELETE) {
strcpy(g->Message, "MySQL table delete not implemented yet\n");
bool rc = MakeDelete(g);
if (!rc && Myc.ExecSQL(g, Query) == RC_NF) {
if (!AftRows)
AftRows = Myc.GetRows();
m_Rc = RC_OK;
} // endif ExecSQL
#endif // 0
} else {
// bool rc = MakeUpdate(g, sqlp->GetProj());
strcpy(g->Message, "MySQL table delete/update not implemented yet\n");
} // endelse
} else
// m_Rc = (Mode == MODE_DELETE) ? MakeDelete(g) : MakeUpdate(g);
m_Rc = MakeCommand(g);
if (m_Rc == RC_FX) {
Myc.Close();
return TRUE;
return true;
} // endif rc
Use = USE_OPEN; // Do it now in case we are recursively called
return FALSE;
Use = USE_OPEN;
return false;
} // end of OpenDB
/***********************************************************************/
@ -975,6 +962,38 @@ char *TDBMYSQL::FindFieldColumn(char *name)
return cp;
} // end of FindFieldColumn
/***********************************************************************/
/* Send an UPDATE or DELETE command to the remote server. */
/***********************************************************************/
int TDBMYSQL::SendCommand(PGLOBAL g)
{
int w;
if (Myc.ExecSQLcmd(g, Query, &w) == RC_NF) {
AftRows = Myc.m_Afrw;
sprintf(g->Message, "%s: %d affected rows", Tabname, AftRows);
PushWarning(g, this, 0); // 0 means a Note
if (trace)
htrc("%s\n", g->Message);
if (w && Myc.ExecSQL(g, "SHOW WARNINGS") == RC_OK) {
// We got warnings from the remote server
while (Myc.Fetch(g, -1) == RC_OK) {
sprintf(g->Message, "%s: (%s) %s", Tabname,
Myc.GetCharField(1), Myc.GetCharField(2));
PushWarning(g, this);
} // endwhile Fetch
Myc.FreeResult();
} // endif w
return RC_EF; // Nothing else to do
} else
return RC_FX; // Error
} // end of SendCommand
/***********************************************************************/
/* Data Base read routine for MYSQL access method. */
/***********************************************************************/
@ -986,6 +1005,9 @@ int TDBMYSQL::ReadDB(PGLOBAL g)
htrc("MySQL ReadDB: R%d Mode=%d key=%p link=%p Kindex=%p\n",
GetTdb_No(), Mode, To_Key_Col, To_Link, To_Kindex);
if (Mode == MODE_UPDATE || Mode == MODE_DELETE)
return SendCommand(g);
/*********************************************************************/
/* Now start the reading process. */
/* Here is the place to fetch the line. */
@ -1041,12 +1063,16 @@ int TDBMYSQL::WriteDB(PGLOBAL g)
} // end of WriteDB
/***********************************************************************/
/* Data Base delete line routine for MYSQL access methods. */
/* Data Base delete all routine for MYSQL access methods. */
/***********************************************************************/
int TDBMYSQL::DeleteDB(PGLOBAL g, int irc)
{
strcpy(g->Message, MSG(NO_MYSQL_DELETE));
return RC_FX;
if (irc == RC_FX)
// Send the DELETE (all) command to the remote table
return (SendCommand(g) == RC_FX) ? RC_FX : RC_OK;
else
return RC_OK; // Ignore
} // end of DeleteDB
/***********************************************************************/
@ -1237,7 +1263,7 @@ void MYSQLCOL::InitBind(PGLOBAL g)
/***********************************************************************/
void MYSQLCOL::ReadColumn(PGLOBAL g)
{
char *buf;
char *p, *buf, tim[20];
int rc;
PTDBMY tdbp = (PTDBMY)To_Tdb;
@ -1257,7 +1283,14 @@ void MYSQLCOL::ReadColumn(PGLOBAL g)
if (trace)
htrc("MySQL ReadColumn: name=%s buf=%s\n", Name, buf);
Value->SetValue_char(buf, min((unsigned)Long, strlen(buf)));
// TODO: have a true way to differenciate temporal values
if (strlen(buf) == 8)
// This is a TIME value
p = strcat(strcpy(tim, "1970-01-01 "), buf);
else
p = buf;
Value->SetValue_char(p, strlen(p));
} else {
if (Nullable)
Value->SetNull(true);
@ -1294,8 +1327,30 @@ void MYSQLCOL::WriteColumn(PGLOBAL g)
/* ------------------------------------------------------------------- */
/***********************************************************************/
/* Implementation of the TDBMYSQL class. */
/* Implementation of the TDBMYEXC class. */
/***********************************************************************/
TDBMYEXC::TDBMYEXC(PMYDEF tdp) : TDBMYSQL(tdp)
{
Cmdlist = NULL;
Cmdcol = NULL;
Shw = false;
Havew = false;
Isw = false;
Warnings = 0;
Mxr = tdp->Mxr;
Nerr = 0;
} // end of TDBMYEXC constructor
TDBMYEXC::TDBMYEXC(PGLOBAL g, PTDBMYX tdbp) : TDBMYSQL(g, tdbp)
{
Cmdlist = tdbp->Cmdlist;
Cmdcol = tdbp->Cmdcol;
Shw = tdbp->Shw;
Havew = tdbp->Havew;
Isw = tdbp->Isw;
Mxr = tdbp->Mxr;
Nerr = tdbp->Nerr;
} // end of TDBMYEXC copy constructor
// Is this really useful ???
PTDB TDBMYEXC::CopyOne(PTABS t)
@ -1331,23 +1386,15 @@ PCOL TDBMYEXC::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
/***********************************************************************/
/* MakeCMD: make the SQL statement to send to MYSQL connection. */
/***********************************************************************/
char *TDBMYEXC::MakeCMD(PGLOBAL g)
PCMD TDBMYEXC::MakeCMD(PGLOBAL g)
{
char *xcmd = NULL;
PCMD 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;
if (!stricmp(Cmdcol, To_Filter->Body) &&
(To_Filter->Op == OP_EQ || To_Filter->Op == OP_IN)) {
xcmd = To_Filter->Cmds;
} else
strcpy(g->Message, "Invalid command specification filter");
@ -1357,7 +1404,7 @@ char *TDBMYEXC::MakeCMD(PGLOBAL g)
} else if (!Srcdef)
strcpy(g->Message, "No Srcdef default command");
else
xcmd = Srcdef;
xcmd = new(g) CMD(g, Srcdef);
return xcmd;
} // end of MakeCMD
@ -1368,7 +1415,7 @@ char *TDBMYEXC::MakeCMD(PGLOBAL g)
int TDBMYEXC::GetMaxSize(PGLOBAL g)
{
if (MaxSize < 0) {
MaxSize = 1;
MaxSize = 10; // a guess
} // endif MaxSize
return MaxSize;
@ -1379,8 +1426,6 @@ int TDBMYEXC::GetMaxSize(PGLOBAL g)
/***********************************************************************/
bool TDBMYEXC::OpenDB(PGLOBAL g)
{
int rc;
if (Use == USE_OPEN) {
strcpy(g->Message, "Multiple execution is not allowed");
return true;
@ -1407,20 +1452,11 @@ bool TDBMYEXC::OpenDB(PGLOBAL g)
/*********************************************************************/
/* Get the command to execute. */
/*********************************************************************/
if (!(Query = MakeCMD(g))) {
if (!(Cmdlist = 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
@ -1429,7 +1465,54 @@ bool TDBMYEXC::OpenDB(PGLOBAL g)
/***********************************************************************/
int TDBMYEXC::ReadDB(PGLOBAL g)
{
return (++N) ? RC_EF : RC_OK;
if (Havew) {
// Process result set from SHOW WARNINGS
if (Myc.Fetch(g, -1) != RC_OK) {
Myc.FreeResult();
Havew = Isw = false;
} else {
N++;
Isw = true;
return RC_OK;
} // endif Fetch
} // endif m_Res
if (Cmdlist) {
// Process query to send
int rc;
do {
Query = Cmdlist->Cmd;
switch (rc = Myc.ExecSQLcmd(g, Query, &Warnings)) {
case RC_NF:
AftRows = Myc.m_Afrw;
strcpy(g->Message, "Affected rows");
break;
case RC_OK:
AftRows = Myc.m_Fields;
strcpy(g->Message, "Result set columns");
break;
case RC_FX:
AftRows = Myc.m_Afrw;
Nerr++;
break;
case RC_INFO:
Shw = true;
} // endswitch rc
Cmdlist = (Nerr > Mxr) ? NULL : Cmdlist->Next;
} while (rc == RC_INFO);
if (Shw && Warnings)
Havew = (Myc.ExecSQL(g, "SHOW WARNINGS") == RC_OK);
++N;
return RC_OK;
} else
return RC_EF;
} // end of ReadDB
/***********************************************************************/
@ -1480,12 +1563,23 @@ 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
if (tdbp->Isw) {
char *buf = NULL;
if (Flag < 3) {
buf = tdbp->Myc.GetCharField(Flag);
Value->SetValue_psz(buf);
} else
Value->Reset();
} else
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;
case 3: Value->SetValue(tdbp->Warnings); break;
default: Value->SetValue_psz("Invalid Flag"); break;
} // endswitch Flag
} // end of ReadColumn

View File

@ -20,6 +20,7 @@ typedef class MYSQLC *PMYC;
/***********************************************************************/
class MYSQLDEF : public TABDEF {/* Logical table description */
friend class TDBMYSQL;
friend class TDBMYEXC;
friend class TDBMCL;
friend class ha_connect;
public:
@ -52,7 +53,10 @@ class MYSQLDEF : public TABDEF {/* Logical table description */
PSZ Username; /* User logon name */
PSZ Password; /* Password logon info */
PSZ Server; /* PServerID */
PSZ Qrystr; /* The original query */
int Portnumber; /* MySQL port number (0 = default) */
int Mxr; /* Maxerr for an Exec table */
int Quoted; /* Identifier quoting level */
bool Isview; /* TRUE if this table is a MySQL view */
bool Bind; /* Use prepared statement on insert */
bool Delayed; /* Delayed insert */
@ -102,9 +106,11 @@ class TDBMYSQL : public TDBASE {
// Internal functions
bool MakeSelect(PGLOBAL g);
bool MakeInsert(PGLOBAL g);
//bool MakeUpdate(PGLOBAL g);
//bool MakeDelete(PGLOBAL g);
int BindColumns(PGLOBAL g);
int MakeCommand(PGLOBAL g);
//int MakeUpdate(PGLOBAL g);
//int MakeDelete(PGLOBAL g);
int SendCommand(PGLOBAL g);
// Members
MYSQLC Myc; // MySQL connection class
@ -118,6 +124,7 @@ class TDBMYSQL : public TDBASE {
char *Server; // The server ID
char *Query; // Points to SQL query
char *Qbuf; // Used for not prepared insert
char *Qrystr; // The original query
bool Fetched; // True when fetch was done
bool Isview; // True if this table is a MySQL view
bool Prep; // Use prepared statement on insert
@ -127,6 +134,7 @@ class TDBMYSQL : public TDBASE {
int N; // The current table index
int Port; // MySQL port number (0 = default)
int Nparm; // The number of statement parameters
int Quoted; // The identifier quoting level
}; // end of class TDBMYSQL
/***********************************************************************/
@ -167,13 +175,12 @@ class MYSQLCOL : public COLBLK {
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;}
// Constructors
TDBMYEXC(PMYDEF tdp);
TDBMYEXC(PGLOBAL g, PTDBMYX tdbp);
// Implementation
//virtual AMT GetAmType(void) {return TYPE_AM_MYSQL;}
virtual AMT GetAmType(void) {return TYPE_AM_MYX;}
virtual PTDB Duplicate(PGLOBAL g) {return (PTDB)new(g) TDBMYEXC(g, this);}
// Methods
@ -203,13 +210,20 @@ class TDBMYEXC : public TDBMYSQL {
protected:
// Internal functions
char *MakeCMD(PGLOBAL g);
PCMD MakeCMD(PGLOBAL g);
//bool MakeSelect(PGLOBAL g);
//bool MakeInsert(PGLOBAL g);
//int BindColumns(PGLOBAL g);
// Members
PCMD Cmdlist; // The commands to execute
char *Cmdcol; // The name of the Xsrc command column
bool Shw; // Show warnings
bool Havew; // True when processing warnings
bool Isw; // True for warning lines
int Warnings; // Warnings number
int Mxr; // Maximum errors before closing
int Nerr; // Number of errors so far
}; // end of class TDBMYEXC
/***********************************************************************/

View File

@ -495,6 +495,7 @@ bool TDBOCCUR::OpenDB(PGLOBAL g)
if (Tdbp->OpenDB(g))
return TRUE;
Use = USE_OPEN;
return ViewColumnList(g);
} // end of OpenDB

View File

@ -3,8 +3,6 @@
#include "tabutil.h"
#define TYPE_AM_OCCUR (AMT)128
typedef class OCCURDEF *POCCURDEF;
typedef class TDBOCCUR *PTDBOCCUR;
typedef class OCCURCOL *POCCURCOL;

View File

@ -90,8 +90,8 @@ extern int num_read, num_there, num_eq[2]; // Statistics
/***********************************************************************/
ODBCDEF::ODBCDEF(void)
{
Connect = Tabname = Tabowner = Tabqual = Srcdef = Qchar = NULL;
Catver = Options = 0;
Connect = Tabname = Tabowner = Tabqual = Srcdef = Qrystr = NULL;
Catver = Options = Quoted = 0;
Xsrc = false;
} // end of ODBCDEF constructor
@ -107,9 +107,11 @@ bool ODBCDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
Tabowner = Cat->GetStringCatInfo(g, "Owner", "");
Tabqual = Cat->GetStringCatInfo(g, "Qualifier", "");
Srcdef = Cat->GetStringCatInfo(g, "Srcdef", NULL);
Qchar = Cat->GetStringCatInfo(g, "Qchar", "");
Qrystr = Cat->GetStringCatInfo(g, "Query_String", "?");
Catver = Cat->GetIntCatInfo("Catver", 2);
Xsrc = Cat->GetBoolCatInfo("Execsrc", FALSE);
Mxr = Cat->GetIntCatInfo("Maxerr", 0);
Quoted = Cat->GetIntCatInfo("Quoted", 0);
Options = ODBConn::noOdbcDialog;
Pseudo = 2; // FILID is Ok but not ROWID
return false;
@ -169,8 +171,9 @@ TDBODBC::TDBODBC(PODEF tdp) : TDBASE(tdp)
Owner = tdp->Tabowner;
Qualifier = tdp->Tabqual;
Srcdef = tdp->Srcdef;
Quote = tdp->GetQchar();
Qrystr = tdp->Qrystr;
Options = tdp->Options;
Quoted = max(0, tdp->GetQuoted());
Rows = tdp->GetElemt();
Catver = tdp->Catver;
} else {
@ -179,12 +182,14 @@ TDBODBC::TDBODBC(PODEF tdp) : TDBASE(tdp)
Owner = NULL;
Qualifier = NULL;
Srcdef = NULL;
Quote = NULL;
Qrystr = NULL;
Options = 0;
Quoted = 0;
Rows = 0;
Catver = 0;
} // endif tdp
Quote = NULL;
Query = NULL;
Count = NULL;
//Where = NULL;
@ -207,6 +212,7 @@ TDBODBC::TDBODBC(PTDBODBC tdbp) : TDBASE(tdbp)
Owner = tdbp->Owner;
Qualifier = tdbp->Qualifier;
Srcdef = tdbp->Srcdef;
Qrystr = tdbp->Qrystr;
Quote = tdbp->Quote;
Query = tdbp->Query;
Count = tdbp->Count;
@ -214,6 +220,7 @@ TDBODBC::TDBODBC(PTDBODBC tdbp) : TDBASE(tdbp)
MulConn = tdbp->MulConn;
DBQ = tdbp->DBQ;
Options = tdbp->Options;
Quoted = tdbp->Quoted;
Rows = tdbp->Rows;
Fpos = tdbp->Fpos;
AftRows = tdbp->AftRows;
@ -395,7 +402,7 @@ char *TDBODBC::MakeSQL(PGLOBAL g, bool cnt)
// Below 14 is length of 'select ' + length of ' from ' + 1
len = (strlen(colist) + strlen(buf) + 14);
len += (To_Filter ? strlen(To_Filter) + 7 : 0);
len += (To_Filter ? strlen(To_Filter->Body) + 7 : 0);
// if (tablep->GetQualifier()) This is used when using a table
// qualp = tablep->GetQualifier(); from anotherPlugDB database but
@ -432,7 +439,7 @@ char *TDBODBC::MakeSQL(PGLOBAL g, bool cnt)
strcat(sql, tabname);
if (To_Filter)
strcat(strcat(sql, " WHERE "), To_Filter);
strcat(strcat(sql, " WHERE "), To_Filter->Body);
return sql;
} // end of MakeSQL
@ -440,21 +447,18 @@ char *TDBODBC::MakeSQL(PGLOBAL g, bool cnt)
/***********************************************************************/
/* MakeInsert: make the Insert statement used with ODBC connection. */
/***********************************************************************/
bool TDBODBC::MakeInsert(PGLOBAL g)
char *TDBODBC::MakeInsert(PGLOBAL g)
{
char *colist, *valist;
char *stmt, *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;
return NULL;
} else {
len += (strlen(colp->GetName()) + 4);
((PODBCCOL)colp)->Rank = ++Nparm;
@ -482,18 +486,18 @@ bool TDBODBC::MakeInsert(PGLOBAL g)
// 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 ");
stmt = (char*)PlugSubAlloc(g, NULL, len);
strcpy(stmt, "INSERT INTO ");
if (Quote)
strcat(strcat(strcat(Query, Quote), TableName), Quote);
strcat(strcat(strcat(stmt, Quote), TableName), Quote);
else
strcat(Query, TableName);
strcat(stmt, TableName);
strcat(strcat(strcat(Query, " ("), colist), ") VALUES (");
strcat(strcat(Query, valist), ")");
strcat(strcat(strcat(stmt, " ("), colist), ") VALUES (");
strcat(strcat(stmt, valist), ")");
return false;
return stmt;
} // end of MakeInsert
/***********************************************************************/
@ -514,6 +518,127 @@ bool TDBODBC::BindParameters(PGLOBAL g)
return false;
} // end of BindParameters
/***********************************************************************/
/* MakeCommand: make the Update or Delete statement to send to the */
/* MySQL server. Limited to remote values and filtering. */
/***********************************************************************/
char *TDBODBC::MakeCommand(PGLOBAL g)
{
char *p, name[68], *qc = Ocp->GetQuoteChar();
char *stmt = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 64);
char *qrystr = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 1);
bool qtd = Quoted > 0;
int i = 0, k = 0;
// Make a lower case copy of the originale query and change
// back ticks to the data source identifier quoting character
do {
qrystr[i] = (Qrystr[i] == '`') ? *qc : tolower(Qrystr[i]);
} while (Qrystr[i++]);
// Check whether the table name is equal to a keyword
// If so, it must be quoted in the original query
strlwr(strcat(strcat(strcpy(name, " "), Name), " "));
if (!strstr(" update delete low_priority ignore quick from ", name))
strlwr(strcpy(name, Name)); // Not a keyword
else
strlwr(strcat(strcat(strcpy(name, qc), Name), qc));
if ((p = strstr(qrystr, name))) {
for (i = 0; i < p - qrystr; i++)
stmt[i] = (Qrystr[i] == '`') ? *qc : Qrystr[i];
stmt[i] = 0;
k = i + (int)strlen(Name);
if (qtd && *(p-1) == ' ')
strcat(strcat(strcat(stmt, qc), TableName), qc);
else
strcat(stmt, TableName);
i = (int)strlen(stmt);
do {
stmt[i++] = (Qrystr[k] == '`') ? *qc : Qrystr[k];
} while (Qrystr[k++]);
} else {
sprintf(g->Message, "Cannot use this %s command",
(Mode == MODE_UPDATE) ? "UPDATE" : "DELETE");
return NULL;
} // endif p
return stmt;
} // end of MakeCommand
#if 0
/***********************************************************************/
/* MakeUpdate: make the SQL statement to send to ODBC connection. */
/***********************************************************************/
char *TDBODBC::MakeUpdate(PGLOBAL g)
{
char *qc, *stmt = NULL, cmd[8], tab[96], end[1024];
stmt = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 64);
memset(end, 0, sizeof(end));
if (sscanf(Qrystr, "%s `%[^`]`%1023c", cmd, tab, end) > 2 ||
sscanf(Qrystr, "%s \"%[^\"]\"%1023c", cmd, tab, end) > 2)
qc = Ocp->GetQuoteChar();
else if (sscanf(Qrystr, "%s %s%1023c", cmd, tab, end) > 2)
qc = (Quoted) ? Quote : "";
else {
strcpy(g->Message, "Cannot use this UPDATE command");
return NULL;
} // endif sscanf
assert(!stricmp(cmd, "update"));
strcat(strcat(strcat(strcpy(stmt, "UPDATE "), qc), TableName), qc);
for (int i = 0; end[i]; i++)
if (end[i] == '`')
end[i] = *qc;
strcat(stmt, end);
return stmt;
} // end of MakeUpdate
/***********************************************************************/
/* MakeDelete: make the SQL statement to send to ODBC connection. */
/***********************************************************************/
char *TDBODBC::MakeDelete(PGLOBAL g)
{
char *qc, *stmt = NULL, cmd[8], from[8], tab[96], end[512];
stmt = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 64);
memset(end, 0, sizeof(end));
if (sscanf(Qrystr, "%s %s `%[^`]`%511c", cmd, from, tab, end) > 2 ||
sscanf(Qrystr, "%s %s \"%[^\"]\"%511c", cmd, from, tab, end) > 2)
qc = Ocp->GetQuoteChar();
else if (sscanf(Qrystr, "%s %s %s%511c", cmd, from, tab, end) > 2)
qc = (Quoted) ? Quote : "";
else {
strcpy(g->Message, "Cannot use this DELETE command");
return NULL;
} // endif sscanf
assert(!stricmp(cmd, "delete") && !stricmp(from, "from"));
strcat(strcat(strcat(strcpy(stmt, "DELETE FROM "), qc), TableName), qc);
if (*end) {
for (int i = 0; end[i]; i++)
if (end[i] == '`')
end[i] = *qc;
strcat(stmt, end);
} // endif end
return stmt;
} // end of MakeDelete
#endif // 0
/***********************************************************************/
/* ResetSize: call by TDBMUL when calculating size estimate. */
/***********************************************************************/
@ -533,7 +658,7 @@ int TDBODBC::GetMaxSize(PGLOBAL g)
{
if (MaxSize < 0) {
// Make MariaDB happy
MaxSize = 100;
MaxSize = (Mode == MODE_DELETE) ? 0 : 10;
#if 0
// This is unuseful and takes time
if (Srcdef) {
@ -616,51 +741,40 @@ bool TDBODBC::OpenDB(PGLOBAL g)
if (Ocp->Open(Connect, Options) < 1)
return true;
else if (Quoted)
Quote = Ocp->GetQuoteChar();
Use = USE_OPEN; // Do it now in case we are recursively called
/*********************************************************************/
/* Allocate whatever is used for getting results. */
/* Make the command and allocate whatever is used for getting results. */
/*********************************************************************/
if (Mode == MODE_READ) {
/*******************************************************************/
/* The issue here is that if max result size is needed, it must be */
/* calculated before the result set for the final data retrieval is*/
/* allocated and the final statement prepared so we call GetMaxSize*/
/* here. It can be a waste of time if the max size is not needed */
/* but currently we always are asking for it (for progress info). */
/*******************************************************************/
GetMaxSize(g); // Will be set for next call
if ((Query = MakeSQL(g, false))) {
for (PODBCCOL colp = (PODBCCOL)Columns; colp;
colp = (PODBCCOL)colp->GetNext())
if (!colp->IsSpecial())
colp->AllocateBuffers(g, Rows);
if (!Query)
if ((Query = MakeSQL(g, false))) {
for (PODBCCOL colp = (PODBCCOL)Columns;
colp; colp = (PODBCCOL)colp->GetNext())
if (!colp->IsSpecial())
colp->AllocateBuffers(g, Rows);
} else {
Ocp->Close();
return true;
rc = ((Rows = Ocp->ExecDirectSQL(Query, (PODBCCOL)Columns)) < 0);
} // endif Query
if (!rc)
rc = ((Rows = Ocp->ExecDirectSQL(Query, (PODBCCOL)Columns)) < 0);
} else if (Mode == MODE_INSERT) {
if (!(rc = MakeInsert(g)))
if ((Query = MakeInsert(g))) {
if (Nparm != Ocp->PrepareSQL(Query)) {
strcpy(g->Message, MSG(PARM_CNT_MISS));
rc = true;
} else
rc = BindParameters(g);
} else {
strcpy(g->Message, "No DELETE/UPDATE of ODBC tablesd");
return true;
} // endelse
} // endif Query
if (rc) {
} else if (Mode == MODE_UPDATE || Mode == MODE_DELETE)
Query = MakeCommand(g);
else
sprintf(g->Message, "Invalid mode %d", Mode);
if (!Query || rc) {
Ocp->Close();
return true;
} // endif rc
@ -691,6 +805,21 @@ int TDBODBC::ReadDB(PGLOBAL g)
htrc("ODBC ReadDB: R%d Mode=%d key=%p link=%p Kindex=%p\n",
GetTdb_No(), Mode, To_Key_Col, To_Link, To_Kindex);
if (Mode == MODE_UPDATE || Mode == MODE_DELETE) {
// Send the UPDATE/DELETE command to the remote table
if (!Ocp->ExecSQLcommand(Query)) {
sprintf(g->Message, "%s: %d affected rows", TableName, AftRows);
if (trace)
htrc("%s\n", g->Message);
PushWarning(g, this, 0); // 0 means a Note
return RC_EF; // Nothing else to do
} else
return RC_FX; // Error
} // endif Mode
if (To_Kindex) {
// Direct access of ODBC tables is not implemented yet
strcpy(g->Message, MSG(NO_ODBC_DIRECT));
@ -720,7 +849,7 @@ int TDBODBC::ReadDB(PGLOBAL g)
/***********************************************************************/
int TDBODBC::WriteDB(PGLOBAL g)
{
int n = Ocp->ExecuteSQL(false);
int n = Ocp->ExecuteSQL();
if (n < 0) {
AftRows = n;
@ -736,8 +865,22 @@ int TDBODBC::WriteDB(PGLOBAL g)
/***********************************************************************/
int TDBODBC::DeleteDB(PGLOBAL g, int irc)
{
strcpy(g->Message, MSG(NO_ODBC_DELETE));
return RC_FX;
if (irc == RC_FX) {
// Send the DELETE (all) command to the remote table
if (!Ocp->ExecSQLcommand(Query)) {
sprintf(g->Message, "%s: %d affected rows", TableName, AftRows);
if (trace)
htrc("%s\n", g->Message);
PushWarning(g, this, 0); // 0 means a Note
return RC_OK; // This is a delete all
} else
return RC_FX; // Error
} else
return RC_OK; // Ignore
} // end of DeleteDB
/***********************************************************************/
@ -751,6 +894,7 @@ void TDBODBC::CloseDB(PGLOBAL g)
// } // endif
if (Ocp)
Ocp->Close();
if (trace)
@ -934,7 +1078,7 @@ void ODBCCOL::AllocateBuffers(PGLOBAL g, int rows)
if (Buf_Type == TYPE_DATE)
Bufp = PlugSubAlloc(g, NULL, rows * sizeof(TIMESTAMP_STRUCT));
else {
Blkp = AllocValBlock(g, NULL, Buf_Type, rows, Long+1, 0, true, false);
Blkp = AllocValBlock(g, NULL, Buf_Type, rows, Long+1, 0, true, false, false);
Bufp = Blkp->GetValPointer();
} // endelse
@ -1004,6 +1148,22 @@ void ODBCCOL::WriteColumn(PGLOBAL g)
/***********************************************************************/
/* Implementation of the TDBODBC class. */
/***********************************************************************/
TDBXDBC::TDBXDBC(PODEF tdp) : TDBODBC(tdp)
{
Cmdlist = NULL;
Cmdcol = NULL;
Mxr = tdp->Mxr;
Nerr = 0;
} // end of TDBXDBC constructor
TDBXDBC::TDBXDBC(PTDBXDBC tdbp) : TDBODBC(tdbp)
{
Cmdlist = tdbp->Cmdlist;
Cmdcol = tdbp->Cmdcol;
Mxr = tdbp->Mxr;
Nerr = tdbp->Nerr;
} // end of TDBXDBC copy constructor
PTDB TDBXDBC::CopyOne(PTABS t)
{
PTDB tp;
@ -1036,23 +1196,15 @@ PCOL TDBXDBC::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
/***********************************************************************/
/* MakeCMD: make the SQL statement to send to ODBC connection. */
/***********************************************************************/
char *TDBXDBC::MakeCMD(PGLOBAL g)
PCMD TDBXDBC::MakeCMD(PGLOBAL g)
{
char *xcmd = NULL;
PCMD 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;
if (!stricmp(Cmdcol, To_Filter->Body) &&
(To_Filter->Op == OP_EQ || To_Filter->Op == OP_IN)) {
xcmd = To_Filter->Cmds;
} else
strcpy(g->Message, "Invalid command specification filter");
@ -1062,7 +1214,7 @@ char *TDBXDBC::MakeCMD(PGLOBAL g)
} else if (!Srcdef)
strcpy(g->Message, "No Srcdef default command");
else
xcmd = Srcdef;
xcmd = new(g) CMD(g, Srcdef);
return xcmd;
} // end of MakeCMD
@ -1088,12 +1240,12 @@ bool TDBXDBC::BindParameters(PGLOBAL g)
#endif // 0
/***********************************************************************/
/* XDBC GetMaxSize: returns table size (always one row). */
/* XDBC GetMaxSize: returns table size (not always one row). */
/***********************************************************************/
int TDBXDBC::GetMaxSize(PGLOBAL g)
{
if (MaxSize < 0)
MaxSize = 1;
MaxSize = 10; // Just a guess
return MaxSize;
} // end of GetMaxSize
@ -1142,19 +1294,12 @@ bool TDBXDBC::OpenDB(PGLOBAL g)
/*********************************************************************/
/* Get the command to execute. */
/*********************************************************************/
if (!(Query = MakeCMD(g))) {
if (!(Cmdlist = 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
@ -1163,18 +1308,18 @@ bool TDBXDBC::OpenDB(PGLOBAL g)
/***********************************************************************/
int TDBXDBC::ReadDB(PGLOBAL g)
{
if (trace)
htrc("XDBC ReadDB: query=%s\n", SVP(Query));
if (Cmdlist) {
Query = Cmdlist->Cmd;
if (Rows--) {
if (!AftRows)
AftRows = Ocp->ExecuteSQL(true);
if (Ocp->ExecSQLcommand(Query))
Nerr++;
Fpos++; // Used for progress info
Cmdlist = (Nerr > Mxr) ? NULL : Cmdlist->Next;
return RC_OK;
} else
return RC_EF;
Fpos++; // Used for progress info
return RC_OK;
} // end of ReadDB
/***********************************************************************/
@ -1186,6 +1331,15 @@ int TDBXDBC::WriteDB(PGLOBAL g)
return RC_FX;
} // end of DeleteDB
/***********************************************************************/
/* Data Base delete line routine for ODBC access method. */
/***********************************************************************/
int TDBXDBC::DeleteDB(PGLOBAL g, int irc)
{
strcpy(g->Message, MSG(NO_ODBC_DELETE));
return RC_FX;
} // end of DeleteDB
/* --------------------------- XSRCCOL ------------------------------- */
/***********************************************************************/

View File

@ -34,7 +34,7 @@ class DllExport ODBCDEF : public TABDEF { /* Logical table description */
PSZ GetTabowner(void) {return Tabowner;}
PSZ GetTabqual(void) {return Tabqual;}
PSZ GetSrcdef(void) {return Srcdef;}
PSZ GetQchar(void) {return (Qchar && *Qchar) ? Qchar : NULL;}
int GetQuoted(void) {return Quoted;}
int GetCatver(void) {return Catver;}
int GetOptions(void) {return Options;}
@ -50,8 +50,11 @@ class DllExport ODBCDEF : public TABDEF { /* Logical table description */
PSZ Tabqual; /* External table qualifier */
PSZ Srcdef; /* The source table SQL definition */
PSZ Qchar; /* Identifier quoting character */
PSZ Qrystr; /* The original query */
int Catver; /* ODBC version for catalog functions */
int Options; /* Open connection options */
int Quoted; /* Identifier quoting level */
int Mxr; /* Maxerr for an Exec table */
bool Xsrc; /* Execution type */
}; // end of ODBCDEF
@ -96,13 +99,14 @@ class TDBODBC : public TDBASE {
protected:
// Internal functions
int Decode(char *utf, char *buf, size_t n);
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 MakeDelete(PGLOBAL g);
char *MakeInsert(PGLOBAL g);
char *MakeCommand(PGLOBAL g);
//bool MakeFilter(PGLOBAL g, bool c);
bool BindParameters(PGLOBAL g);
//char *MakeUpdate(PGLOBAL g);
//char *MakeDelete(PGLOBAL g);
// Members
ODBConn *Ocp; // Points to an ODBC connection class
@ -118,7 +122,9 @@ class TDBODBC : public TDBASE {
char *Quote; // The identifier quoting character
char *MulConn; // Used for multiple ODBC tables
char *DBQ; // The address part of Connect string
char *Qrystr; // The original query
int Options; // Connect options
int Quoted; // The identifier quoting level
int Fpos; // Position of last read record
int AftRows; // The number of affected rows
int Rows; // Rowset size
@ -179,12 +185,12 @@ 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;}
// Constructors
TDBXDBC(PODEF tdp = NULL);
TDBXDBC(PTDBXDBC tdbp);
// Implementation
//virtual AMT GetAmType(void) {return TYPE_AM_ODBC;}
virtual AMT GetAmType(void) {return TYPE_AM_XDBC;}
virtual PTDB Duplicate(PGLOBAL g)
{return (PTDB)new(g) TDBXDBC(this);}
@ -204,16 +210,19 @@ class TDBXDBC : public TDBODBC {
virtual bool OpenDB(PGLOBAL g);
virtual int ReadDB(PGLOBAL g);
virtual int WriteDB(PGLOBAL g);
//virtual int DeleteDB(PGLOBAL g, int irc);
virtual int DeleteDB(PGLOBAL g, int irc);
//virtual void CloseDB(PGLOBAL g);
protected:
// Internal functions
char *MakeCMD(PGLOBAL g);
PCMD MakeCMD(PGLOBAL g);
//bool BindParameters(PGLOBAL g);
// Members
PCMD Cmdlist; // The commands to execute
char *Cmdcol; // The name of the Xsrc command column
int Mxr; // Maximum errors before closing
int Nerr; // Number of errors so far
}; // end of class TDBXDBC
/***********************************************************************/

View File

@ -607,6 +607,8 @@ bool TDBPIVOT::OpenDB(PGLOBAL g)
if (Tdbp->OpenDB(g))
return TRUE;
Use = USE_OPEN; // Do it now in case we are recursively called
/*********************************************************************/
/* Make all required pivot columns for object views. */
/*********************************************************************/

View File

@ -295,15 +295,18 @@ bool TDBTBL::InitTableList(PGLOBAL g)
/***********************************************************************/
bool TDBTBL::TestFil(PGLOBAL g, PFIL filp, PTABLE tabp)
{
char *fil, op[8], tn[NAME_LEN];
char *body, *fil, op[8], tn[NAME_LEN];
bool neg;
if (!filp)
return TRUE;
else if (strstr(filp, " OR ") || strstr(filp, " AND "))
else
body = filp->Body;
if (strstr(body, " OR ") || strstr(body, " AND "))
return TRUE; // Not handled yet
else
fil = filp + (*filp == '(' ? 1 : 0);
fil = body + (*body == '(' ? 1 : 0);
if (sscanf(fil, "TABID %s", op) != 1)
return TRUE; // ignore invalid filter

View File

@ -495,6 +495,7 @@ bool TDBPRX::OpenDB(PGLOBAL g)
if (Tdbp->OpenDB(g))
return TRUE;
Use = USE_OPEN;
return FALSE;
} // end of OpenDB

View File

@ -6,8 +6,6 @@
//#include "tabtbl.h"
#define TYPE_AM_PRX (AMT)129
typedef class PRXDEF *PPRXDEF;
typedef class TDBPRX *PTDBPRX;
typedef class XXLCOL *PXXLCOL;

View File

@ -81,7 +81,7 @@ char *strerror(int num);
/* Conversion of block values allowed conditionally for insert only. */
/***********************************************************************/
PVBLK AllocValBlock(PGLOBAL, void *, int, int, int, int,
bool check = true, bool blank = true);
bool check = true, bool blank = true, bool un = false);
/* --------------------------- Class VCTDEF -------------------------- */

View File

@ -480,18 +480,19 @@ bool TDBWMI::Initialize(PGLOBAL g)
/***********************************************************************/
void TDBWMI::DoubleSlash(PGLOBAL g)
{
if (To_Filter && strchr(To_Filter, '\\')) {
char *buf = (char*)PlugSubAlloc(g, NULL, strlen(To_Filter) * 2);
if (To_Filter && strchr(To_Filter->Body, '\\')) {
char *body = To_Filter->Body;
char *buf = (char*)PlugSubAlloc(g, NULL, strlen(body) * 2);
int i = 0, k = 0;
do {
if (To_Filter[i] == '\\')
if (body[i] == '\\')
buf[k++] = '\\';
buf[k++] = To_Filter[i];
} while (To_Filter[i++]);
buf[k++] = body[i];
} while (body[i++]);
To_Filter = buf;
To_Filter->Body = buf;
} // endif To_Filter
} // end of DoubleSlash
@ -539,13 +540,13 @@ char *TDBWMI::MakeWQL(PGLOBAL g)
// Below 14 is length of 'select ' + length of ' from ' + 1
len = (strlen(colist) + strlen(Wclass) + 14);
len += (To_Filter ? strlen(To_Filter) + 7 : 0);
len += (To_Filter ? strlen(To_Filter->Body) + 7 : 0);
wql = (char*)PlugSubAlloc(g, NULL, len);
strcat(strcat(strcpy(wql, "SELECT "), colist), " FROM ");
strcat(wql, Wclass);
if (To_Filter)
strcat(strcat(wql, " WHERE "), To_Filter);
strcat(strcat(wql, " WHERE "), To_Filter->Body);
return wql;
} // end of MakeWQL
@ -666,6 +667,8 @@ bool TDBWMI::OpenDB(PGLOBAL g)
} else
DoubleSlash(g);
Use = USE_OPEN; // Do it now in case we are recursively called
/*********************************************************************/
/* Initialize the WMI processing. */
/*********************************************************************/

View File

@ -193,6 +193,7 @@ bool TDBXCL::OpenDB(PGLOBAL g)
if (Tdbp->OpenDB(g))
return TRUE;
Use = USE_OPEN;
return FALSE;
} // end of OpenDB

View File

@ -3,8 +3,6 @@
#include "tabutil.h"
#define TYPE_AM_XCOL (AMT)124
typedef class XCLDEF *PXCLDEF;
typedef class TDBXCL *PTDBXCL;
typedef class XCLCOL *PXCLCOL;

View File

@ -1,5 +1,5 @@
/************ Valblk C++ Functions Source Code File (.CPP) *************/
/* Name: VALBLK.CPP Version 1.7 */
/* Name: VALBLK.CPP Version 2.0 */
/* */
/* (C) Copyright to the author Olivier BERTRAND 2005-2013 */
/* */
@ -16,7 +16,7 @@
/* types of objects, we shall have more classes to update. */
/* This is why we are now using a template class for many types. */
/* Currently the only implemented types are PSZ, chars, int, short, */
/* DATE, longlong, and double. Shortly we should add more types. */
/* DATE, longlong, double and tiny. Fix numeric ones can be unsigned. */
/***********************************************************************/
/***********************************************************************/
@ -46,7 +46,7 @@
/* AllocValBlock: allocate a VALBLK according to type. */
/***********************************************************************/
PVBLK AllocValBlock(PGLOBAL g, void *mp, int type, int nval, int len,
int prec, bool check, bool blank)
int prec, bool check, bool blank, bool un)
{
PVBLK blkp;
@ -64,22 +64,38 @@ PVBLK AllocValBlock(PGLOBAL g, void *mp, int type, int nval, int len,
break;
case TYPE_SHORT:
blkp = new(g) TYPBLK<short>(mp, nval, type);
if (un)
blkp = new(g) TYPBLK<ushort>(mp, nval, type, 0, true);
else
blkp = new(g) TYPBLK<short>(mp, nval, type);
break;
case TYPE_INT:
blkp = new(g) TYPBLK<int>(mp, nval, type);
if (un)
blkp = new(g) TYPBLK<uint>(mp, nval, type, 0, true);
else
blkp = new(g) TYPBLK<int>(mp, nval, type);
break;
case TYPE_DATE: // ?????
blkp = new(g) DATBLK(mp, nval);
break;
case TYPE_BIGINT:
blkp = new(g) TYPBLK<longlong>(mp, nval, type);
if (un)
blkp = new(g) TYPBLK<ulonglong>(mp, nval, type, 0, true);
else
blkp = new(g) TYPBLK<longlong>(mp, nval, type);
break;
case TYPE_FLOAT:
blkp = new(g) TYPBLK<double>(mp, nval, prec, type);
blkp = new(g) TYPBLK<double>(mp, nval, type, prec);
break;
case TYPE_TINY:
blkp = new(g) TYPBLK<char>(mp, nval, type);
if (un)
blkp = new(g) TYPBLK<uchar>(mp, nval, type, 0, true);
else
blkp = new(g) TYPBLK<char>(mp, nval, type);
break;
default:
sprintf(g->Message, MSG(BAD_VALBLK_TYPE), type);
@ -95,12 +111,13 @@ PVBLK AllocValBlock(PGLOBAL g, void *mp, int type, int nval, int len,
/***********************************************************************/
/* Constructor. */
/***********************************************************************/
VALBLK::VALBLK(void *mp, int type, int nval)
VALBLK::VALBLK(void *mp, int type, int nval, bool un)
{
Blkp = mp;
To_Nulls = NULL;
Check = true;
Nullable = false;
Unsigned = un;
Type = type;
Nval = nval;
Prec = 0;
@ -195,23 +212,15 @@ void VALBLK::ChkTyp(PVBLK vb)
/* -------------------------- Class TYPBLK --------------------------- */
/***********************************************************************/
/* Constructors. */
/* Constructor. */
/***********************************************************************/
template <class TYPE>
TYPBLK<TYPE>::TYPBLK(void *mp, int nval, int type)
: VALBLK(mp, type, nval), Typp((TYPE*&)Blkp)
TYPBLK<TYPE>::TYPBLK(void *mp, int nval, int type, int prec, bool un)
: VALBLK(mp, type, nval, un), Typp((TYPE*&)Blkp)
{
Fmt = GetFmt(Type);
} // end of TYPBLK constructor
template <class TYPE>
TYPBLK<TYPE>::TYPBLK(void *mp, int nval, int prec, int type)
: VALBLK(mp, type, nval), Typp((TYPE*&)Blkp)
{
DBUG_ASSERT(Type == TYPE_FLOAT);
Prec = prec;
Fmt = GetFmt(Type);
} // end of DBLBLK constructor
} // end of TYPBLK constructor
/***********************************************************************/
/* Initialization routine. */
@ -249,14 +258,26 @@ template <>
int TYPBLK<int>::GetTypedValue(PVAL valp)
{return valp->GetIntValue();}
template <>
uint TYPBLK<uint>::GetTypedValue(PVAL valp)
{return valp->GetUIntValue();}
template <>
short TYPBLK<short>::GetTypedValue(PVAL valp)
{return valp->GetShortValue();}
template <>
ushort TYPBLK<ushort>::GetTypedValue(PVAL valp)
{return valp->GetUShortValue();}
template <>
longlong TYPBLK<longlong>::GetTypedValue(PVAL valp)
{return valp->GetBigintValue();}
template <>
ulonglong TYPBLK<ulonglong>::GetTypedValue(PVAL valp)
{return valp->GetUBigintValue();}
template <>
double TYPBLK<double>::GetTypedValue(PVAL valp)
{return valp->GetFloatValue();}
@ -265,6 +286,10 @@ template <>
char TYPBLK<char>::GetTypedValue(PVAL valp)
{return valp->GetTinyValue();}
template <>
uchar TYPBLK<uchar>::GetTypedValue(PVAL valp)
{return valp->GetUTinyValue();}
/***********************************************************************/
/* Set one value in a block from a zero terminated string. */
/***********************************************************************/
@ -286,13 +311,21 @@ void TYPBLK<TYPE>::SetValue(PSZ p, int n)
template <>
int TYPBLK<int>::GetTypedValue(PSZ p) {return atol(p);}
template <>
uint TYPBLK<uint>::GetTypedValue(PSZ p) {return (unsigned)atol(p);}
template <>
short TYPBLK<short>::GetTypedValue(PSZ p) {return (short)atoi(p);}
template <>
ushort TYPBLK<ushort>::GetTypedValue(PSZ p) {return (ushort)atoi(p);}
template <>
longlong TYPBLK<longlong>::GetTypedValue(PSZ p) {return atoll(p);}
template <>
ulonglong TYPBLK<ulonglong>::GetTypedValue(PSZ p) {return (unsigned)atoll(p);}
template <>
double TYPBLK<double>::GetTypedValue(PSZ p) {return atof(p);}
template <>
char TYPBLK<char>::GetTypedValue(PSZ p) {return (char)atoi(p);}
template <>
uchar TYPBLK<uchar>::GetTypedValue(PSZ p) {return (uchar)atoi(p);}
/***********************************************************************/
/* Set one value in a block from an array of characters. */
@ -333,14 +366,26 @@ template <>
int TYPBLK<int>::GetTypedValue(PVBLK blk, int n)
{return blk->GetIntValue(n);}
template <>
uint TYPBLK<uint>::GetTypedValue(PVBLK blk, int n)
{return blk->GetUIntValue(n);}
template <>
short TYPBLK<short>::GetTypedValue(PVBLK blk, int n)
{return blk->GetShortValue(n);}
template <>
ushort TYPBLK<ushort>::GetTypedValue(PVBLK blk, int n)
{return blk->GetUShortValue(n);}
template <>
longlong TYPBLK<longlong>::GetTypedValue(PVBLK blk, int n)
{return blk->GetBigintValue(n);}
template <>
ulonglong TYPBLK<ulonglong>::GetTypedValue(PVBLK blk, int n)
{return blk->GetUBigintValue(n);}
template <>
double TYPBLK<double>::GetTypedValue(PVBLK blk, int n)
{return blk->GetFloatValue(n);}
@ -349,6 +394,10 @@ template <>
char TYPBLK<char>::GetTypedValue(PVBLK blk, int n)
{return blk->GetTinyValue(n);}
template <>
uchar TYPBLK<uchar>::GetTypedValue(PVBLK blk, int n)
{return blk->GetUTinyValue(n);}
#if 0
/***********************************************************************/
/* Set many values in a block from values in another block. */
@ -516,6 +565,14 @@ short CHRBLK::GetShortValue(int n)
return (short)atoi((char *)GetValPtrEx(n));
} // end of GetShortValue
/***********************************************************************/
/* Return the value of the nth element converted to ushort. */
/***********************************************************************/
ushort CHRBLK::GetUShortValue(int n)
{
return (ushort)atoi((char *)GetValPtrEx(n));
} // end of GetShortValue
/***********************************************************************/
/* Return the value of the nth element converted to int. */
/***********************************************************************/
@ -524,6 +581,14 @@ int CHRBLK::GetIntValue(int n)
return atol((char *)GetValPtrEx(n));
} // end of GetIntValue
/***********************************************************************/
/* Return the value of the nth element converted to uint. */
/***********************************************************************/
uint CHRBLK::GetUIntValue(int n)
{
return (unsigned)atol((char *)GetValPtrEx(n));
} // end of GetIntValue
/***********************************************************************/
/* Return the value of the nth element converted to big int. */
/***********************************************************************/
@ -532,6 +597,14 @@ longlong CHRBLK::GetBigintValue(int n)
return atoll((char *)GetValPtrEx(n));
} // end of GetBigintValue
/***********************************************************************/
/* Return the value of the nth element converted to unsigned big int. */
/***********************************************************************/
ulonglong CHRBLK::GetUBigintValue(int n)
{
return (unsigned)atoll((char *)GetValPtrEx(n));
} // end of GetBigintValue
/***********************************************************************/
/* Return the value of the nth element converted to double. */
/***********************************************************************/
@ -548,6 +621,14 @@ char CHRBLK::GetTinyValue(int n)
return (char)atoi((char *)GetValPtrEx(n));
} // end of GetTinyValue
/***********************************************************************/
/* Return the value of the nth element converted to unsigned tiny int.*/
/***********************************************************************/
uchar CHRBLK::GetUTinyValue(int n)
{
return (uchar)atoi((char *)GetValPtrEx(n));
} // end of GetTinyValue
/***********************************************************************/
/* Set one value in a block. */
/***********************************************************************/

View File

@ -1,5 +1,5 @@
/*************** Valblk H Declares Source Code File (.H) ***************/
/* Name: VALBLK.H Version 1.9 */
/* Name: VALBLK.H Version 2.0 */
/* */
/* (C) Copyright to the author Olivier BERTRAND 2005-2013 */
/* */
@ -18,8 +18,9 @@
/***********************************************************************/
/* Utility used to allocate value blocks. */
/***********************************************************************/
DllExport PVBLK AllocValBlock(PGLOBAL, void*, int, int, int, int, bool, bool);
const char *GetFmt(int type);
DllExport PVBLK AllocValBlock(PGLOBAL, void*, int, int, int, int,
bool, bool, bool);
const char *GetFmt(int type, bool un = false);
/***********************************************************************/
/* Class VALBLK represent a base class for variable blocks. */
@ -28,7 +29,7 @@ class VALBLK : public BLOCK {
//friend void SemColData(PGLOBAL g, PSEM semp);
public:
// Constructors
VALBLK(void *mp, int type, int nval);
VALBLK(void *mp, int type, int nval, bool un = false);
// Implementation
int GetNval(void) {return Nval;}
@ -48,10 +49,14 @@ class VALBLK : public BLOCK {
virtual int GetVlen(void) = 0;
virtual PSZ GetCharValue(int n);
virtual short GetShortValue(int n) = 0;
virtual ushort GetUShortValue(int n) = 0;
virtual int GetIntValue(int n) = 0;
virtual uint GetUIntValue(int n) = 0;
virtual longlong GetBigintValue(int n) = 0;
virtual ulonglong GetUBigintValue(int n) = 0;
virtual double GetFloatValue(int n) = 0;
virtual char GetTinyValue(int n) = 0;
virtual uchar GetUTinyValue(int n) = 0;
virtual void ReAlloc(void *mp, int n) {Blkp = mp; Nval = n;}
virtual void Reset(int n) = 0;
virtual bool SetFormat(PGLOBAL g, PSZ fmt, int len, int year = 0);
@ -60,10 +65,14 @@ class VALBLK : public BLOCK {
// Methods
virtual void SetValue(short sval, int n) {assert(false);}
virtual void SetValue(ushort sval, int n) {assert(false);}
virtual void SetValue(int lval, int n) {assert(false);}
virtual void SetValue(uint lval, int n) {assert(false);}
virtual void SetValue(longlong lval, int n) {assert(false);}
virtual void SetValue(ulonglong lval, int n) {assert(false);}
virtual void SetValue(double fval, int n) {assert(false);}
virtual void SetValue(char cval, int n) {assert(false);}
virtual void SetValue(uchar cval, int n) {assert(false);}
virtual void SetValue(PSZ sp, int n) {assert(false);}
virtual void SetValue(char *sp, uint len, int n) {assert(false);}
virtual void SetValue(PVAL valp, int n) = 0;
@ -94,6 +103,7 @@ class VALBLK : public BLOCK {
void *Blkp; // To value block
bool Check; // If true SetValue types must match
bool Nullable; // True if values can be null
bool Unsigned; // True if values are unsigned
int Type; // Type of individual values
int Nval; // Max number of values in block
int Prec; // Precision of float values
@ -106,18 +116,22 @@ template <class TYPE>
class TYPBLK : public VALBLK {
public:
// Constructors
TYPBLK(void *mp, int size, int type);
TYPBLK(void *mp, int size, int prec, int type);
TYPBLK(void *mp, int size, int type, int prec = 0, bool un = false);
//TYPBLK(void *mp, int size, int prec, int type);
// Implementation
virtual void Init(PGLOBAL g, bool check);
virtual int GetVlen(void) {return sizeof(TYPE);}
//virtual PSZ GetCharValue(int n);
virtual short GetShortValue(int n) {return (short)Typp[n];}
virtual ushort GetUShortValue(int n) {return (ushort)Typp[n];}
virtual int GetIntValue(int n) {return (int)Typp[n];}
virtual uint GetUIntValue(int n) {return (uint)Typp[n];}
virtual longlong GetBigintValue(int n) {return (longlong)Typp[n];}
virtual ulonglong GetUBigintValue(int n) {return (ulonglong)Typp[n];}
virtual double GetFloatValue(int n) {return (double)Typp[n];}
virtual char GetTinyValue(int n) {return (char)Typp[n];}
virtual uchar GetUTinyValue(int n) {return (uchar)Typp[n];}
virtual void Reset(int n) {Typp[n] = 0;}
// Methods
@ -125,14 +139,22 @@ class TYPBLK : public VALBLK {
virtual void SetValue(char *sp, uint len, int n);
virtual void SetValue(short sval, int n)
{Typp[n] = (TYPE)sval; SetNull(n, false);}
virtual void SetValue(ushort sval, int n)
{Typp[n] = (TYPE)sval; SetNull(n, false);}
virtual void SetValue(int lval, int n)
{Typp[n] = (TYPE)lval; SetNull(n, false);}
virtual void SetValue(uint lval, int n)
{Typp[n] = (TYPE)lval; SetNull(n, false);}
virtual void SetValue(longlong lval, int n)
{Typp[n] = (TYPE)lval; SetNull(n, false);}
virtual void SetValue(ulonglong lval, int n)
{Typp[n] = (TYPE)lval; SetNull(n, false);}
virtual void SetValue(double fval, int n)
{Typp[n] = (TYPE)fval; SetNull(n, false);}
virtual void SetValue(char cval, int n)
{Typp[n] = (TYPE)cval; SetNull(n, false);}
virtual void SetValue(uchar cval, int n)
{Typp[n] = (TYPE)cval; SetNull(n, false);}
virtual void SetValue(PVAL valp, int n);
virtual void SetValue(PVBLK pv, int n1, int n2);
//virtual void SetValues(PVBLK pv, int k, int n);
@ -168,10 +190,14 @@ class CHRBLK : public VALBLK {
virtual int GetVlen(void) {return Long;}
virtual PSZ GetCharValue(int n);
virtual short GetShortValue(int n);
virtual ushort GetUShortValue(int n);
virtual int GetIntValue(int n);
virtual uint GetUIntValue(int n);
virtual longlong GetBigintValue(int n);
virtual ulonglong GetUBigintValue(int n);
virtual double GetFloatValue(int n);
virtual char GetTinyValue(int n);
virtual uchar GetUTinyValue(int n);
virtual void Reset(int n);
virtual void SetPrec(int p) {Ci = (p != 0);}
virtual bool IsCi(void) {return Ci;}
@ -217,10 +243,14 @@ class STRBLK : public VALBLK {
virtual int GetVlen(void) {return sizeof(PSZ);}
virtual PSZ GetCharValue(int n) {return Strp[n];}
virtual short GetShortValue(int n) {return (short)atoi(Strp[n]);}
virtual ushort GetUShortValue(int n) {return (ushort)atoi(Strp[n]);}
virtual int GetIntValue(int n) {return atol(Strp[n]);}
virtual uint GetUIntValue(int n) {return (unsigned)atol(Strp[n]);}
virtual longlong GetBigintValue(int n) {return atoll(Strp[n]);}
virtual ulonglong GetUBigintValue(int n) {return (unsigned)atoll(Strp[n]);}
virtual double GetFloatValue(int n) {return atof(Strp[n]);}
virtual char GetTinyValue(int n) {return (char)atoi(Strp[n]);}
virtual uchar GetUTinyValue(int n) {return (uchar)atoi(Strp[n]);}
virtual void Reset(int n) {Strp[n] = NULL;}
// Methods

View File

@ -1,5 +1,5 @@
/************* Value C++ Functions Source Code File (.CPP) *************/
/* Name: VALUE.CPP Version 2.2 */
/* Name: VALUE.CPP Version 2.3 */
/* */
/* (C) Copyright to the author Olivier BERTRAND 2001-2013 */
/* */
@ -20,7 +20,7 @@
/* functions used on one family only. The drawback is that for new */
/* types of objects, we shall have more classes to update. */
/* Currently the only implemented types are STRING, INT, SHORT, TINY, */
/* DATE and LONGLONG. Shortly we should add at least UNSIGNED types. */
/* DATE and LONGLONG. Recently we added some UNSIGNED types. */
/***********************************************************************/
/***********************************************************************/
@ -92,40 +92,12 @@ PSZ strlwr(PSZ s);
}
#endif // !WIN32
#ifdef NOT_USED
/***********************************************************************/
/* Returns the bitmap representing the conditions that must not be */
/* met when returning from TestValue for a given operator. */
/* Bit one is EQ, bit 2 is LT, and bit 3 is GT. */
/***********************************************************************/
static BYTE OpBmp(PGLOBAL g, OPVAL opc)
{
BYTE bt;
switch (opc) {
case OP_IN:
case OP_EQ: bt = 0x06; break;
case OP_NE: bt = 0x01; break;
case OP_GT: bt = 0x03; break;
case OP_GE: bt = 0x02; break;
case OP_LT: bt = 0x05; break;
case OP_LE: bt = 0x04; break;
case OP_EXIST: bt = 0x00; break;
default:
sprintf(g->Message, MSG(BAD_FILTER_OP), opc);
longjmp(g->jumper[g->jump_level], 777);
} // endswitch opc
return bt;
} // end of OpBmp
#endif
/***********************************************************************/
/* GetTypeName: returns the PlugDB internal type name. */
/***********************************************************************/
PSZ GetTypeName(int type)
{
PSZ name = "UNKNOWN";
PSZ name;
switch (type) {
case TYPE_STRING: name = "CHAR"; break;
@ -135,6 +107,7 @@ PSZ GetTypeName(int type)
case TYPE_DATE: name = "DATE"; break;
case TYPE_FLOAT: name = "FLOAT"; break;
case TYPE_TINY: name = "TINY"; break;
default: name = "UNKNOWN"; break;
} // endswitch type
return name;
@ -153,7 +126,6 @@ int GetTypeSize(int type, int len)
case TYPE_DATE: len = sizeof(int); break;
case TYPE_FLOAT: len = sizeof(double); break;
case TYPE_TINY: len = sizeof(char); break;
break;
default: len = 0;
} // endswitch type
@ -236,21 +208,22 @@ bool IsTypeNum(int type)
/***********************************************************************/
/* GetFmt: returns the format to use with a typed value. */
/***********************************************************************/
const char *GetFmt(int type)
const char *GetFmt(int type, bool un)
{
const char *fmt;
switch (type) {
case TYPE_STRING: fmt = "%s"; break;
case TYPE_SHORT: fmt = "%hd"; break;
case TYPE_BIGINT: fmt = "%lld"; break;
case TYPE_FLOAT: fmt = "%.*lf"; break;
default: fmt = "%d"; break;
case TYPE_STRING: fmt = "%s"; break;
case TYPE_SHORT: fmt = (un) ? "%hu" : "%hd"; break;
case TYPE_BIGINT: fmt = (un) ? "%llu" : "%lld"; break;
case TYPE_FLOAT: fmt = "%.*lf"; break;
default: fmt = (un) ? "%u" : "%d"; break;
} // endswitch Type
return fmt;
} // end of GetFmt
#if 0
/***********************************************************************/
/* ConvertType: what this function does is to determine the type to */
/* which should be converted a value so no precision would be lost. */
@ -297,6 +270,7 @@ int ConvertType(int target, int type, CONV kind, bool match)
} // endswitch kind
} // end of ConvertType
#endif // 0
/***********************************************************************/
/* AllocateConstant: allocates a constant Value. */
@ -322,7 +296,7 @@ PVAL AllocateValue(PGLOBAL g, void *value, short type)
valp = new(g) TYPVAL<longlong>(*(longlong*)value, TYPE_BIGINT);
break;
case TYPE_FLOAT:
valp = new(g) TYPVAL<double>(*(double *)value, TYPE_FLOAT);
valp = new(g) TYPVAL<double>(*(double *)value, TYPE_FLOAT, 2);
break;
case TYPE_TINY:
valp = new(g) TYPVAL<char>(*(char *)value, TYPE_TINY);
@ -339,8 +313,7 @@ PVAL AllocateValue(PGLOBAL g, void *value, short type)
/***********************************************************************/
/* Allocate a variable Value according to type, length and precision. */
/***********************************************************************/
PVAL AllocateValue(PGLOBAL g, int type, int len, int prec,
PSZ dom, PCATLG cat)
PVAL AllocateValue(PGLOBAL g, int type, int len, int prec, PSZ fmt)
{
PVAL valp;
@ -349,22 +322,38 @@ PVAL AllocateValue(PGLOBAL g, int type, int len, int prec,
valp = new(g) TYPVAL<PSZ>(g, (PSZ)NULL, len, prec);
break;
case TYPE_DATE:
valp = new(g) DTVAL(g, len, prec, dom);
valp = new(g) DTVAL(g, len, prec, fmt);
break;
case TYPE_INT:
valp = new(g) TYPVAL<int>((int)0, TYPE_INT);
if (prec)
valp = new(g) TYPVAL<uint>((uint)0, TYPE_INT, 0, true);
else
valp = new(g) TYPVAL<int>((int)0, TYPE_INT);
break;
case TYPE_BIGINT:
valp = new(g) TYPVAL<longlong>((longlong)0, TYPE_BIGINT);
if (prec)
valp = new(g) TYPVAL<ulonglong>((ulonglong)0, TYPE_BIGINT, 0, true);
else
valp = new(g) TYPVAL<longlong>((longlong)0, TYPE_BIGINT);
break;
case TYPE_SHORT:
valp = new(g) TYPVAL<short>((short)0, TYPE_SHORT);
if (prec)
valp = new(g) TYPVAL<ushort>((ushort)0, TYPE_SHORT, 0, true);
else
valp = new(g) TYPVAL<short>((short)0, TYPE_SHORT);
break;
case TYPE_FLOAT:
valp = new(g) TYPVAL<double>(0.0, prec, TYPE_FLOAT);
valp = new(g) TYPVAL<double>(0.0, TYPE_FLOAT, prec);
break;
case TYPE_TINY:
valp = new(g) TYPVAL<char>((char)0, TYPE_TINY);
if (prec)
valp = new(g) TYPVAL<uchar>((uchar)0, TYPE_TINY, 0, true);
else
valp = new(g) TYPVAL<char>((char)0, TYPE_TINY);
break;
default:
sprintf(g->Message, MSG(BAD_VALUE_TYPE), type);
@ -379,9 +368,10 @@ PVAL AllocateValue(PGLOBAL g, int type, int len, int prec,
/* Allocate a constant Value converted to newtype. */
/* Can also be used to copy a Value eventually converted. */
/***********************************************************************/
PVAL AllocateValue(PGLOBAL g, PVAL valp, int newtype)
PVAL AllocateValue(PGLOBAL g, PVAL valp, int newtype, int uns)
{
PSZ p, sp;
PSZ p, sp;
bool un = (uns < 0) ? false : (uns > 0) ? true : valp->IsUnsigned();
if (newtype == TYPE_VOID) // Means allocate a value of the same type
newtype = valp->GetType();
@ -396,22 +386,42 @@ PVAL AllocateValue(PGLOBAL g, PVAL valp, int newtype)
valp = new(g) TYPVAL<PSZ>(g, p, valp->GetValLen(), valp->GetValPrec());
break;
case TYPE_SHORT:
valp = new(g) TYPVAL<short>(valp->GetShortValue(), TYPE_SHORT);
if (un)
valp = new(g) TYPVAL<ushort>(valp->GetUShortValue(),
TYPE_SHORT, 0, true);
else
valp = new(g) TYPVAL<short>(valp->GetShortValue(), TYPE_SHORT);
break;
case TYPE_INT:
valp = new(g) TYPVAL<int>(valp->GetIntValue(), TYPE_INT);
if (un)
valp = new(g) TYPVAL<uint>(valp->GetUIntValue(), TYPE_INT, 0, true);
else
valp = new(g) TYPVAL<int>(valp->GetIntValue(), TYPE_INT);
break;
case TYPE_BIGINT:
valp = new(g) TYPVAL<longlong>(valp->GetBigintValue(), TYPE_BIGINT);
if (un)
valp = new(g) TYPVAL<ulonglong>(valp->GetUBigintValue(),
TYPE_BIGINT, 0, true);
else
valp = new(g) TYPVAL<longlong>(valp->GetBigintValue(), TYPE_BIGINT);
break;
case TYPE_DATE:
valp = new(g) DTVAL(g, valp->GetIntValue());
break;
case TYPE_FLOAT:
valp = new(g) TYPVAL<double>(valp->GetFloatValue(), TYPE_FLOAT);
valp = new(g) TYPVAL<double>(valp->GetFloatValue(), TYPE_FLOAT,
valp->GetValPrec());
break;
case TYPE_TINY:
valp = new(g) TYPVAL<char>(valp->GetTinyValue(), TYPE_TINY);
if (un)
valp = new(g) TYPVAL<uchar>(valp->GetUTinyValue(),
TYPE_TINY, 0, true);
else
valp = new(g) TYPVAL<char>(valp->GetTinyValue(), TYPE_TINY);
break;
default:
sprintf(g->Message, MSG(BAD_VALUE_TYPE), newtype);
@ -428,14 +438,15 @@ PVAL AllocateValue(PGLOBAL g, PVAL valp, int newtype)
/***********************************************************************/
/* Class VALUE protected constructor. */
/***********************************************************************/
VALUE::VALUE(int type) : Type(type)
VALUE::VALUE(int type, bool un) : Type(type)
{
Fmt = GetFmt(Type);
Xfmt = GetXfmt();
Null = false;
Nullable = false;
Unsigned = un;
Clen = 0;
Prec = 0;
Fmt = GetFmt(Type, Unsigned);
Xfmt = GetXfmt();
} // end of VALUE constructor
/***********************************************************************/
@ -446,11 +457,11 @@ const char *VALUE::GetXfmt(void)
const char *fmt;
switch (Type) {
case TYPE_STRING: fmt = "%*s"; break;
case TYPE_SHORT: fmt = "%*hd"; break;
case TYPE_BIGINT: fmt = "%*lld"; break;
case TYPE_FLOAT: fmt = "%*.*lf"; break;
default: fmt = "%*d"; break;
case TYPE_STRING: fmt = "%*s"; break;
case TYPE_SHORT: fmt = (Unsigned) ? "%*hu" : "%*hd"; break;
case TYPE_BIGINT: fmt = (Unsigned) ? "%*llu" : "%*lld"; break;
case TYPE_FLOAT: fmt = "%*.*lf"; break;
default: fmt = (Unsigned) ? "%*u" : "%*d"; break;
} // endswitch Type
return fmt;
@ -462,22 +473,11 @@ const char *VALUE::GetXfmt(void)
/* TYPVAL public constructor from a constant typed value. */
/***********************************************************************/
template <class TYPE>
TYPVAL<TYPE>::TYPVAL(TYPE n, int type) : VALUE(type)
TYPVAL<TYPE>::TYPVAL(TYPE n, int type, int prec, bool un)
: VALUE(type, un)
{
Tval = n;
Clen = sizeof(TYPE);
Prec = (Type == TYPE_FLOAT) ? 2 : 0;
} // end of TYPVAL constructor
/***********************************************************************/
/* TYPVAL public constructor from typed value. */
/***********************************************************************/
template <class TYPE>
TYPVAL<TYPE>::TYPVAL(TYPE n, int prec, int type) : VALUE(type)
{
assert(Type == TYPE_FLOAT);
Tval = n;
Clen = sizeof(TYPE);
Prec = prec;
} // end of TYPVAL constructor
@ -522,14 +522,26 @@ template <>
short TYPVAL<short>::GetTypedValue(PVAL valp)
{return valp->GetShortValue();}
template <>
ushort TYPVAL<ushort>::GetTypedValue(PVAL valp)
{return valp->GetUShortValue();}
template <>
int TYPVAL<int>::GetTypedValue(PVAL valp)
{return valp->GetIntValue();}
template <>
uint TYPVAL<uint>::GetTypedValue(PVAL valp)
{return valp->GetUIntValue();}
template <>
longlong TYPVAL<longlong>::GetTypedValue(PVAL valp)
{return valp->GetBigintValue();}
template <>
ulonglong TYPVAL<ulonglong>::GetTypedValue(PVAL valp)
{return valp->GetUBigintValue();}
template <>
double TYPVAL<double>::GetTypedValue(PVAL valp)
{return valp->GetFloatValue();}
@ -538,6 +550,10 @@ template <>
char TYPVAL<char>::GetTypedValue(PVAL valp)
{return valp->GetTinyValue();}
template <>
uchar TYPVAL<uchar>::GetTypedValue(PVAL valp)
{return valp->GetUTinyValue();}
/***********************************************************************/
/* TYPVAL SetValue: convert chars extracted from a line to TYPE value.*/
/***********************************************************************/
@ -545,7 +561,7 @@ template <class TYPE>
void TYPVAL<TYPE>::SetValue_char(char *p, int n)
{
char *p2, buf[32];
bool minus;
bool minus = false;
for (p2 = p + n; p < p2 && *p == ' '; p++) ;
@ -570,7 +586,7 @@ void TYPVAL<TYPE>::SetValue_char(char *p, int n)
} // endswitch *p
if (minus && Tval)
Tval = - Tval;
Tval = (-(signed)Tval) ? -(signed)Tval : Tval;
if (trace > 1)
htrc(strcat(strcat(strcpy(buf, " setting %s to: "), Fmt), "\n"),
@ -622,13 +638,21 @@ void TYPVAL<TYPE>::SetValue_psz(PSZ s)
template <>
int TYPVAL<int>::GetTypedValue(PSZ s) {return atol(s);}
template <>
uint TYPVAL<uint>::GetTypedValue(PSZ s) {return (unsigned)atol(s);}
template <>
short TYPVAL<short>::GetTypedValue(PSZ s) {return (short)atoi(s);}
template <>
ushort TYPVAL<ushort>::GetTypedValue(PSZ s) {return (ushort)atoi(s);}
template <>
longlong TYPVAL<longlong>::GetTypedValue(PSZ s) {return atoll(s);}
template <>
ulonglong TYPVAL<ulonglong>::GetTypedValue(PSZ s) {return (unsigned)atoll(s);}
template <>
double TYPVAL<double>::GetTypedValue(PSZ s) {return atof(s);}
template <>
char TYPVAL<char>::GetTypedValue(PSZ s) {return (char)atoi(s);}
template <>
uchar TYPVAL<uchar>::GetTypedValue(PSZ s) {return (uchar)atoi(s);}
/***********************************************************************/
/* TYPVAL SetValue: set value with a TYPE extracted from a block. */
@ -644,14 +668,26 @@ template <>
int TYPVAL<int>::GetTypedValue(PVBLK blk, int n)
{return blk->GetIntValue(n);}
template <>
uint TYPVAL<uint>::GetTypedValue(PVBLK blk, int n)
{return (unsigned)blk->GetIntValue(n);}
template <>
short TYPVAL<short>::GetTypedValue(PVBLK blk, int n)
{return blk->GetShortValue(n);}
template <>
ushort TYPVAL<ushort>::GetTypedValue(PVBLK blk, int n)
{return (unsigned)blk->GetShortValue(n);}
template <>
longlong TYPVAL<longlong>::GetTypedValue(PVBLK blk, int n)
{return blk->GetBigintValue(n);}
template <>
ulonglong TYPVAL<ulonglong>::GetTypedValue(PVBLK blk, int n)
{return (unsigned)blk->GetBigintValue(n);}
template <>
double TYPVAL<double>::GetTypedValue(PVBLK blk, int n)
{return blk->GetFloatValue(n);}
@ -660,6 +696,10 @@ template <>
char TYPVAL<char>::GetTypedValue(PVBLK blk, int n)
{return blk->GetTinyValue(n);}
template <>
uchar TYPVAL<uchar>::GetTypedValue(PVBLK blk, int n)
{return (unsigned)blk->GetTinyValue(n);}
/***********************************************************************/
/* TYPVAL SetBinValue: with bytes extracted from a line. */
/***********************************************************************/
@ -684,7 +724,7 @@ bool TYPVAL<TYPE>::GetBinValue(void *buf, int buflen, bool go)
// be different from the variable length because no conversion is done.
// Therefore this test is useless anyway.
//#if defined(_DEBUG)
// if (sizeof(int) > buflen)
// if (sizeof(TYPE) > buflen)
// return true;
//#endif
@ -730,6 +770,7 @@ char *TYPVAL<double>::GetCharString(char *p)
return p;
} // end of GetCharString
#if 0
/***********************************************************************/
/* TYPVAL GetShortString: get short representation of a typed value. */
/***********************************************************************/
@ -779,6 +820,7 @@ char *TYPVAL<TYPE>::GetTinyString(char *p, int n)
sprintf(p, "%*d", n, (int)(char)Tval);
return p;
} // end of GetIntString
#endif // 0
/***********************************************************************/
/* TYPVAL compare value with another Value. */
@ -875,7 +917,6 @@ TYPVAL<PSZ>::TYPVAL(PSZ s) : VALUE(TYPE_STRING)
TYPVAL<PSZ>::TYPVAL(PGLOBAL g, PSZ s, int n, int c)
: VALUE(TYPE_STRING)
{
assert(Type == TYPE_STRING);
Len = (g) ? n : strlen(s);
if (!s) {
@ -981,6 +1022,24 @@ void TYPVAL<PSZ>::SetValue(int n)
Null = false;
} // end of SetValue
/***********************************************************************/
/* STRING SetValue: get the character representation of an uint. */
/***********************************************************************/
void TYPVAL<PSZ>::SetValue(uint n)
{
char buf[16];
PGLOBAL& g = Global;
int k = sprintf(buf, "%u", n);
if (k > Len) {
sprintf(g->Message, MSG(VALSTR_TOO_LONG), buf, Len);
longjmp(g->jumper[g->jump_level], 138);
} else
SetValue_psz(buf);
Null = false;
} // end of SetValue
/***********************************************************************/
/* STRING SetValue: get the character representation of a short int. */
/***********************************************************************/
@ -990,6 +1049,15 @@ void TYPVAL<PSZ>::SetValue(short i)
Null = false;
} // end of SetValue
/***********************************************************************/
/* STRING SetValue: get the character representation of a ushort int. */
/***********************************************************************/
void TYPVAL<PSZ>::SetValue(ushort i)
{
SetValue((uint)i);
Null = false;
} // end of SetValue
/***********************************************************************/
/* STRING SetValue: get the character representation of a big integer.*/
/***********************************************************************/
@ -1008,6 +1076,24 @@ void TYPVAL<PSZ>::SetValue(longlong n)
Null = false;
} // end of SetValue
/***********************************************************************/
/* STRING SetValue: get the character representation of a big integer.*/
/***********************************************************************/
void TYPVAL<PSZ>::SetValue(ulonglong n)
{
char buf[24];
PGLOBAL& g = Global;
int k = sprintf(buf, "%llu", n);
if (k > Len) {
sprintf(g->Message, MSG(VALSTR_TOO_LONG), buf, Len);
longjmp(g->jumper[g->jump_level], 138);
} else
SetValue_psz(buf);
Null = false;
} // end of SetValue
/***********************************************************************/
/* STRING SetValue: get the character representation of a double. */
/***********************************************************************/
@ -1042,6 +1128,15 @@ void TYPVAL<PSZ>::SetValue(char c)
Null = false;
} // end of SetValue
/***********************************************************************/
/* STRING SetValue: get the character representation of a tiny int. */
/***********************************************************************/
void TYPVAL<PSZ>::SetValue(uchar c)
{
SetValue((uint)c);
Null = false;
} // end of SetValue
/***********************************************************************/
/* STRING SetBinValue: fill string with chars extracted from a line. */
/***********************************************************************/
@ -1086,6 +1181,7 @@ char *TYPVAL<PSZ>::GetCharString(char *p)
return Strp;
} // end of GetCharString
#if 0
/***********************************************************************/
/* STRING GetShortString: get short representation of a char value. */
/***********************************************************************/
@ -1130,6 +1226,7 @@ char *TYPVAL<PSZ>::GetTinyString(char *p, int n)
sprintf(p, "%*d", n, (Null) ? 0 : (char)atoi(Strp));
return p;
} // end of GetIntString
#endif // 0
/***********************************************************************/
/* STRING compare value with another Value. */

View File

@ -1,5 +1,5 @@
/**************** Value H Declares Source Code File (.H) ***************/
/* Name: VALUE.H Version 1.9 */
/* Name: VALUE.H Version 2.0 */
/* */
/* (C) Copyright to the author Olivier BERTRAND 2001-2013 */
/* */
@ -45,16 +45,16 @@ DllExport PSZ GetTypeName(int);
DllExport int GetTypeSize(int, int);
#ifdef ODBC_SUPPORT
/* This function is exported for use in EOM table type DLLs */
DllExport int TranslateSQLType(int stp, int prec, int& len);
DllExport int TranslateSQLType(int stp, int prec, int& len, char& v);
#endif
DllExport char *GetFormatType(int);
DllExport int GetFormatType(char);
DllExport bool IsTypeChar(int type);
DllExport bool IsTypeNum(int type);
DllExport int ConvertType(int, int, CONV, bool match = false);
DllExport PVAL AllocateValue(PGLOBAL, PVAL, int = TYPE_VOID);
DllExport PVAL AllocateValue(PGLOBAL, int, int len = 0, int prec = 2,
PSZ dom = NULL, PCATLG cat = NULL);
//lExport int ConvertType(int, int, CONV, bool match = false);
DllExport PVAL AllocateValue(PGLOBAL, PVAL, int = TYPE_VOID, int = 0);
DllExport PVAL AllocateValue(PGLOBAL, int, int len = 0, int prec = 0,
PSZ fmt = NULL);
/***********************************************************************/
/* Class VALUE represents a constant or variable of any valid type. */
@ -68,6 +68,7 @@ class DllExport VALUE : public BLOCK {
virtual bool IsTypeNum(void) = 0;
virtual bool IsZero(void) = 0;
virtual bool IsCi(void) {return false;}
virtual bool IsUnsigned(void) {return Unsigned;}
virtual void Reset(void) = 0;
virtual int GetSize(void) = 0;
virtual int GetValLen(void) = 0;
@ -75,9 +76,13 @@ class DllExport VALUE : public BLOCK {
virtual int GetLength(void) {return 1;}
virtual PSZ GetCharValue(void) {assert(false); return NULL;}
virtual char GetTinyValue(void) {assert(false); return 0;}
virtual uchar GetUTinyValue(void) {assert(false); return 0;}
virtual short GetShortValue(void) {assert(false); return 0;}
virtual ushort GetUShortValue(void) {assert(false); return 0;}
virtual int GetIntValue(void) = 0;
virtual uint GetUIntValue(void) = 0;
virtual longlong GetBigintValue(void) = 0;
virtual ulonglong GetUBigintValue(void) = 0;
virtual double GetFloatValue(void) = 0;
virtual void *GetTo_Val(void) = 0;
virtual void SetPrec(int prec) {Prec = prec;}
@ -94,20 +99,24 @@ class DllExport VALUE : public BLOCK {
virtual void SetValue_char(char *p, int n) = 0;
virtual void SetValue_psz(PSZ s) = 0;
virtual void SetValue(char c) {assert(false);}
virtual void SetValue(uchar c) {assert(false);}
virtual void SetValue(short i) {assert(false);}
virtual void SetValue(ushort i) {assert(false);}
virtual void SetValue(int n) {assert(false);}
virtual void SetValue(uint n) {assert(false);}
virtual void SetValue(longlong n) {assert(false);}
virtual void SetValue(ulonglong n) {assert(false);}
virtual void SetValue(double f) {assert(false);}
virtual void SetValue_pvblk(PVBLK blk, int n) = 0;
virtual void SetBinValue(void *p) = 0;
virtual bool GetBinValue(void *buf, int buflen, bool go) = 0;
virtual char *ShowValue(char *buf, int len = 0) = 0;
virtual char *GetCharString(char *p) = 0;
virtual char *GetShortString(char *p, int n) {return "#####";}
virtual char *GetIntString(char *p, int n) = 0;
virtual char *GetBigintString(char *p, int n) = 0;
virtual char *GetFloatString(char *p, int n, int prec) = 0;
virtual char *GetTinyString(char *p, int n) {return "?";}
//virtual char *GetShortString(char *p, int n) {return "#####";}
//virtual char *GetIntString(char *p, int n) = 0;
//virtual char *GetBigintString(char *p, int n) = 0;
//virtual char *GetFloatString(char *p, int n, int prec) = 0;
//virtual char *GetTinyString(char *p, int n) {return "?";}
virtual bool IsEqual(PVAL vp, bool chktype) = 0;
virtual bool FormatValue(PVAL vp, char *fmt) = 0;
@ -116,7 +125,7 @@ class DllExport VALUE : public BLOCK {
const char *GetXfmt(void);
// Constructor used by derived classes
VALUE(int type);
VALUE(int type, bool un = false);
// Members
PGLOBAL Global; // To reduce arglist
@ -124,6 +133,7 @@ class DllExport VALUE : public BLOCK {
const char *Xfmt;
bool Nullable; // True if value can be null
bool Null; // True if value is null
bool Unsigned; // True if unsigned
int Type; // The value type
int Clen; // Internal value length
int Prec;
@ -135,9 +145,8 @@ class DllExport VALUE : public BLOCK {
template <class TYPE>
class DllExport TYPVAL : public VALUE {
public:
// Constructors
TYPVAL(TYPE n, int type);
TYPVAL(TYPE n, int prec, int type);
// Constructor
TYPVAL(TYPE n, int type, int prec = 0, bool un = false);
// Implementation
virtual bool IsTypeNum(void) {return true;}
@ -148,9 +157,13 @@ class DllExport TYPVAL : public VALUE {
virtual int GetSize(void) {return sizeof(TYPE);}
virtual PSZ GetCharValue(void) {return VALUE::GetCharValue();}
virtual char GetTinyValue(void) {return (char)Tval;}
virtual uchar GetUTinyValue(void) {return (uchar)Tval;}
virtual short GetShortValue(void) {return (short)Tval;}
virtual ushort GetUShortValue(void) {return (ushort)Tval;}
virtual int GetIntValue(void) {return (int)Tval;}
virtual uint GetUIntValue(void) {return (uint)Tval;}
virtual longlong GetBigintValue(void) {return (longlong)Tval;}
virtual ulonglong GetUBigintValue(void) {return (ulonglong)Tval;}
virtual double GetFloatValue(void) {return (double)Tval;}
virtual void *GetTo_Val(void) {return &Tval;}
@ -159,20 +172,24 @@ class DllExport TYPVAL : public VALUE {
virtual void SetValue_char(char *p, int n);
virtual void SetValue_psz(PSZ s);
virtual void SetValue(char c) {Tval = (TYPE)c; Null = false;}
virtual void SetValue(uchar c) {Tval = (TYPE)c; Null = false;}
virtual void SetValue(short i) {Tval = (TYPE)i; Null = false;}
virtual void SetValue(ushort i) {Tval = (TYPE)i; Null = false;}
virtual void SetValue(int n) {Tval = (TYPE)n; Null = false;}
virtual void SetValue(uint n) {Tval = (TYPE)n; Null = false;}
virtual void SetValue(longlong n) {Tval = (TYPE)n; Null = false;}
virtual void SetValue(ulonglong n) {Tval = (TYPE)n; Null = false;}
virtual void SetValue(double f) {Tval = (TYPE)f; Null = false;}
virtual void SetValue_pvblk(PVBLK blk, int n);
virtual void SetBinValue(void *p);
virtual bool GetBinValue(void *buf, int buflen, bool go);
virtual char *ShowValue(char *buf, int);
virtual char *GetCharString(char *p);
virtual char *GetShortString(char *p, int n);
virtual char *GetIntString(char *p, int n);
virtual char *GetBigintString(char *p, int n);
virtual char *GetFloatString(char *p, int n, int prec = -1);
virtual char *GetTinyString(char *p, int n);
//virtual char *GetShortString(char *p, int n);
//virtual char *GetIntString(char *p, int n);
//virtual char *GetBigintString(char *p, int n);
//virtual char *GetFloatString(char *p, int n, int prec = -1);
//virtual char *GetTinyString(char *p, int n);
virtual bool IsEqual(PVAL vp, bool chktype);
virtual bool SetConstFormat(PGLOBAL, FORMAT&);
virtual bool FormatValue(PVAL vp, char *fmt);
@ -211,9 +228,13 @@ class DllExport TYPVAL<PSZ>: public VALUE {
virtual int GetSize(void) {return (Strp) ? strlen(Strp) : 0;}
virtual PSZ GetCharValue(void) {return Strp;}
virtual char GetTinyValue(void) {return (char)atoi(Strp);}
virtual uchar GetUTinyValue(void) {return (uchar)atoi(Strp);}
virtual short GetShortValue(void) {return (short)atoi(Strp);}
virtual ushort GetUShortValue(void) {return (ushort)atoi(Strp);}
virtual int GetIntValue(void) {return atol(Strp);}
virtual uint GetUIntValue(void) {return (uint)atol(Strp);}
virtual longlong GetBigintValue(void) {return atoll(Strp);}
virtual ulonglong GetUBigintValue(void) {return (ulonglong)atoll(Strp);}
virtual double GetFloatValue(void) {return atof(Strp);}
virtual void *GetTo_Val(void) {return Strp;}
virtual void SetPrec(int prec) {Ci = prec != 0;}
@ -224,30 +245,34 @@ class DllExport TYPVAL<PSZ>: public VALUE {
virtual void SetValue_psz(PSZ s);
virtual void SetValue_pvblk(PVBLK blk, int n);
virtual void SetValue(char c);
virtual void SetValue(uchar c);
virtual void SetValue(short i);
virtual void SetValue(ushort i);
virtual void SetValue(int n);
virtual void SetValue(uint n);
virtual void SetValue(longlong n);
virtual void SetValue(ulonglong n);
virtual void SetValue(double f);
virtual void SetBinValue(void *p);
virtual bool GetBinValue(void *buf, int buflen, bool go);
virtual char *ShowValue(char *buf, int);
virtual char *GetCharString(char *p);
virtual char *GetShortString(char *p, int n);
virtual char *GetIntString(char *p, int n);
virtual char *GetBigintString(char *p, int n);
virtual char *GetFloatString(char *p, int n, int prec = -1);
virtual char *GetTinyString(char *p, int n);
//virtual char *GetShortString(char *p, int n);
//virtual char *GetIntString(char *p, int n);
//virtual char *GetBigintString(char *p, int n);
//virtual char *GetFloatString(char *p, int n, int prec = -1);
//virtual char *GetTinyString(char *p, int n);
virtual bool IsEqual(PVAL vp, bool chktype);
virtual bool FormatValue(PVAL vp, char *fmt);
virtual bool SetConstFormat(PGLOBAL, FORMAT&);
// Specialized functions
template <class T>
T GetValue_as(T type) {return Strp;}
int GetValue_as(int type) {return atol(Strp);}
short GetValue_as(short type) {return (short)atoi(Strp);}
longlong GetValue_as(longlong type) {return atoll(Strp);}
double GetValue_as(double type) {return atof(Strp);}
//template <class T>
//T GetValue_as(T type) {return Strp;}
//int GetValue_as(int type) {return atol(Strp);}
//short GetValue_as(short type) {return (short)atoi(Strp);}
//longlong GetValue_as(longlong type) {return atoll(Strp);}
//double GetValue_as(double type) {return atof(Strp);}
// Members
PSZ Strp;

View File

@ -66,7 +66,7 @@ extern MBLOCK Nmblk; /* Used to initialize MBLOCK's */
/* to have rows filled by blanks to be compatible with QRY blocks. */
/***********************************************************************/
PVBLK AllocValBlock(PGLOBAL, void *, int, int, int, int,
bool check = true, bool blank = true);
bool check = true, bool blank = true, bool un = false);
/***********************************************************************/
/* Check whether we have to create/update permanent indexes. */
@ -2919,7 +2919,7 @@ void KXYCOL::SetValue(PCOL colp, int i)
assert (Kblp != NULL);
#endif
Kblp->SetValue(colp->GetValue(), (int)i);
Kblp->SetValue(colp->GetValue(), i);
} // end of SetValue
/***********************************************************************/
@ -2970,7 +2970,7 @@ void KXYCOL::FillValue(PVAL valp)
int KXYCOL::Compare(int i1, int i2)
{
// Do the actual comparison between values.
register int k = (int)Kblp->CompVal((int)i1, (int)i2);
register int k = Kblp->CompVal(i1, i2);
#ifdef DEBUG2
htrc("Compare done result=%d\n", k);
@ -2991,7 +2991,7 @@ int KXYCOL::CompVal(int i)
htrc("Compare done result=%d\n", k);
return k;
#endif
return (int)Kblp->CompVal(Valp, (int)i);
return Kblp->CompVal(Valp, i);
} // end of CompVal
/***********************************************************************/
@ -3000,7 +3000,7 @@ int KXYCOL::CompVal(int i)
int KXYCOL::CompBval(int i)
{
// Do the actual comparison between key values.
return (int)Blkp->CompVal(Valp, (int)i);
return Blkp->CompVal(Valp, i);
} // end of CompBval
/***********************************************************************/

View File

@ -18,8 +18,28 @@
#include "colblk.h"
#include "m_ctype.h"
//pedef class INDEXDEF *PIXDEF;
typedef char *PFIL; // Specific to CONNECT
typedef class CMD *PCMD;
// Commands executed by XDBC and MYX tables
class CMD : public BLOCK {
public:
// Constructor
CMD(PGLOBAL g, char *cmd) {
Cmd = (char*)PlugSubAlloc(g, NULL, strlen(cmd) + 1);
strcpy(Cmd, cmd); Next = NULL; }
// Members
PCMD Next;
char *Cmd;
}; // end of class CMD
// Filter passed all tables
typedef struct _filter {
char *Body;
OPVAL Op;
PCMD Cmds;
} FILTER, *PFIL;
typedef class TDBCAT *PTDBCAT;
typedef class CATCOL *PCATCOL;
@ -39,24 +59,16 @@ class DllExport TBX: public BLOCK { // Base class for OPJOIN and TDB classes.
inline PFIL GetFilter(void) {return To_Filter;}
inline void SetOrig(PTBX txp) {To_Orig = txp;}
inline void SetFilter(PFIL fp) {To_Filter = fp;}
//inline JTYPE GetJtype(void) {return Jtype;}
//inline void SetJtype(JTYPE jt) {Jtype = jt;}
//inline PFIL GetNoleft(void) {return To_Noleft;}
//inline void SetNoleft(PFIL fp) {To_Noleft = fp;}
// Methods
virtual bool IsSame(PTBX tp) {return tp == this;}
//virtual bool Include(PTBX tbxp) = 0;
//virtual bool CheckFilter(void) = 0;
virtual int GetTdb_No(void) = 0; // Convenience during conversion
virtual PTDB GetNext(void) = 0;
//virtual int GetMaxSame(PGLOBAL) = 0;
virtual int Cardinality(PGLOBAL) = 0;
virtual int GetMaxSize(PGLOBAL) = 0;
virtual int GetProgMax(PGLOBAL) = 0;
virtual int GetProgCur(void) = 0;
virtual int GetBadLines(void) {return 0;}
//virtual bool IsJoin(void) = 0;
virtual PTBX Copy(PTABS t) = 0;
protected:
@ -66,8 +78,6 @@ class DllExport TBX: public BLOCK { // Base class for OPJOIN and TDB classes.
// Members
PTBX To_Orig; // Pointer to original if it is a copy
PFIL To_Filter;
//PFIL To_Noleft; // To filter not involved in LEFT JOIN
//JTYPE Jtype;
TUSE Use;
}; // end of class TBX