summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOlivier Bertrand <bertrandop@gmail.com>2013-05-19 19:25:06 +0200
committerOlivier Bertrand <bertrandop@gmail.com>2013-05-19 19:25:06 +0200
commitc035bde34c3a5a63451b51031d508a425ce9a3ae (patch)
tree40f513d803531c29a04dd18934ab20e799fba964
parent3c76e0e2ad05229ea1718b6e9c3dce85d75aaa4d (diff)
downloadmariadb-git-c035bde34c3a5a63451b51031d508a425ce9a3ae.tar.gz
- Allowing views and queries as parameters for PROXY base tables
NOTE: Checking for looping references cannot be done when using views as parameters. This should not be allowed on production servers and should be dependant on a system variable and/or on speciel grant. modified: storage/connect/CMakeLists.txt storage/connect/connect.cc storage/connect/ha_connect.cc storage/connect/myconn.cpp storage/connect/myconn.h storage/connect/mysql-test/connect/r/fmt.result storage/connect/mysql-test/connect/r/pivot.result storage/connect/mysql-test/connect/t/fmt.test storage/connect/mysql-test/connect/t/pivot.test storage/connect/plgdbsem.h storage/connect/plugutil.c storage/connect/tabcol.cpp storage/connect/tabcol.h storage/connect/tabfmt.cpp storage/connect/tabmysql.cpp storage/connect/tabmysql.h storage/connect/taboccur.cpp storage/connect/taboccur.h storage/connect/tabpivot.cpp storage/connect/tabpivot.h storage/connect/tabtbl.cpp storage/connect/tabutil.cpp storage/connect/tabutil.h storage/connect/xtable.h
-rw-r--r--storage/connect/CMakeLists.txt2
-rw-r--r--storage/connect/connect.cc20
-rw-r--r--storage/connect/ha_connect.cc80
-rw-r--r--storage/connect/myconn.cpp38
-rw-r--r--storage/connect/myconn.h7
-rw-r--r--storage/connect/mysql-test/connect/r/fmt.result4
-rw-r--r--storage/connect/mysql-test/connect/r/pivot.result6
-rw-r--r--storage/connect/mysql-test/connect/t/fmt.test170
-rw-r--r--storage/connect/mysql-test/connect/t/pivot.test289
-rw-r--r--storage/connect/plgdbsem.h4
-rw-r--r--storage/connect/plugutil.c5
-rw-r--r--storage/connect/tabcol.cpp20
-rw-r--r--storage/connect/tabcol.h16
-rw-r--r--storage/connect/tabfmt.cpp22
-rw-r--r--storage/connect/tabmysql.cpp185
-rw-r--r--storage/connect/tabmysql.h14
-rw-r--r--storage/connect/taboccur.cpp172
-rw-r--r--storage/connect/taboccur.h23
-rw-r--r--storage/connect/tabpivot.cpp1003
-rw-r--r--storage/connect/tabpivot.h101
-rw-r--r--storage/connect/tabtbl.cpp4
-rw-r--r--storage/connect/tabutil.cpp95
-rw-r--r--storage/connect/tabutil.h3
-rw-r--r--storage/connect/xtable.h1
24 files changed, 900 insertions, 1384 deletions
diff --git a/storage/connect/CMakeLists.txt b/storage/connect/CMakeLists.txt
index d3663c5eee3..86dddcdb892 100644
--- a/storage/connect/CMakeLists.txt
+++ b/storage/connect/CMakeLists.txt
@@ -178,7 +178,7 @@ OPTION(CONNECT_WITH_MYSQL
IF(CONNECT_WITH_MYSQL)
SET(CONNECT_SOURCES ${CONNECT_SOURCES}
- myconn.cpp myconn.h tabmysql.cpp tabxml.h)
+ myconn.cpp myconn.h tabmysql.cpp tabmysql.h)
add_definitions(-DMYSQL_SUPPORT)
IF(NOT UNIX)
#
diff --git a/storage/connect/connect.cc b/storage/connect/connect.cc
index 6ae730f20b2..7d9456c3259 100644
--- a/storage/connect/connect.cc
+++ b/storage/connect/connect.cc
@@ -71,10 +71,7 @@ int rename_file_ext(const char *from, const char *to,const char *ext);
PGLOBAL CntExit(PGLOBAL g)
{
if (g) {
- PDBUSER dup= PlgGetUser(g);
-
CntEndDB(g);
- free(dup);
if (g->Activityp)
delete g->Activityp;
@@ -94,13 +91,10 @@ void CntEndDB(PGLOBAL g)
PDBUSER dbuserp= PlgGetUser(g);
if (dbuserp) {
- if (dbuserp->Catalog) {
+ if (dbuserp->Catalog)
delete dbuserp->Catalog;
- dbuserp->Catalog= NULL;
- } // endif Catalog
- *dbuserp->Name= '\0';
-// *dbuserp->Work= '\0';
+ free(dbuserp);
} // endif dbuserp
} // end of CntEndDB
@@ -258,10 +252,12 @@ bool CntOpenTable(PGLOBAL g, PTDB tdbp, MODE mode, char *c1, char *c2,
return true;
} // endif tdbp
- if (!c1)
- // Allocate all column blocks for that table
- tdbp->ColDB(g, NULL, 0);
- else for (p= c1; *p; p+= n) {
+ if (!c1) {
+ if (mode == MODE_INSERT)
+ // Allocate all column blocks for that table
+ tdbp->ColDB(g, NULL, 0);
+
+ } else for (p= c1; *p; p+= n) {
// Allocate only used column blocks
if (xtrace)
printf("Allocating column %s\n", p);
diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc
index a4611c83ffe..9bc0d2a9942 100644
--- a/storage/connect/ha_connect.cc
+++ b/storage/connect/ha_connect.cc
@@ -696,7 +696,9 @@ bool ha_connect::GetBooleanOption(char *opname, bool bdef)
char *pv;
PTOS options= GetTableOptionStruct(table);
- if (!options)
+ if (!stricmp(opname, "View"))
+ opval= (tshp) ? tshp->is_view : table->s->is_view;
+ else if (!options)
;
else if (!stricmp(opname, "Mapped"))
opval= options->mapped;
@@ -838,7 +840,7 @@ void *ha_connect::GetColumnOption(void *field, PCOLINFO pcf)
} else
fldp= (tshp) ? tshp->field : table->field;
- if (!(fp= *fldp))
+ if (!fldp || !(fp= *fldp))
return NULL;
// Get the CONNECT field options structure
@@ -1843,11 +1845,13 @@ int ha_connect::open(const char *name, int mode, uint test_if_locked)
// Try to get the user if possible
xp= GetUser(ha_thd(), xp);
- PGLOBAL g= xp->g;
+ PGLOBAL g= (xp) ? xp->g : NULL;
// Try to set the database environment
if (g)
rc= (CntCheckDB(g, this, name)) ? (-2) : 0;
+ else
+ rc= HA_ERR_INTERNAL_ERROR;
DBUG_RETURN(rc);
} // end of open
@@ -2809,6 +2813,10 @@ int ha_connect::external_lock(THD *thd, int lock_type)
bool oldsep= ((PCHK)g->Xchk)->oldsep;
bool newsep= ((PCHK)g->Xchk)->newsep;
PTDBDOS tdp= (PTDBDOS)(tdbp ? tdbp : GetTDB(g));
+
+ if (!tdp)
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+
PDOSDEF ddp= (PDOSDEF)tdp->GetDef();
PIXDEF xp, xp1, xp2, drp=NULL, adp= NULL;
PIXDEF oldpix= ((PCHK)g->Xchk)->oldpix;
@@ -3300,7 +3308,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
{
char spc= ',', qch= 0;
const char *fncn= "?";
- const char *user, *fn, *db, *host, *pwd, *prt, *sep, *tbl; // *csn;
+ const char *user, *fn, *db, *host, *pwd, *prt, *sep, *tbl, *src;
char *tab, *dsn;
#if defined(WIN32)
char *nsp= NULL, *cls= NULL;
@@ -3324,16 +3332,17 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
sql.copy(STRING_WITH_LEN("CREATE TABLE whatever ("), system_charset_info);
- user= host= pwd= prt= tbl= dsn= NULL;
+ user= host= pwd= prt= tbl= src= dsn= NULL;
// Get the useful create options
- ttp= GetTypeID(topt->type);
- fn= topt->filename;
- tab= (char*)topt->tabname;
- db= topt->dbname;
+ ttp= GetTypeID(topt->type);
+ fn= topt->filename;
+ tab= (char*)topt->tabname;
+ src= topt->srcdef;
+ db= topt->dbname;
fncn= topt->catfunc;
fnc= GetFuncID(fncn);
- sep= topt->separator;
+ sep= topt->separator;
spc= (!sep || !strcmp(sep, "\\t")) ? '\t' : *sep;
qch= topt->qchar ? *topt->qchar : topt->quoted >= 0 ? '"' : 0;
hdr= (int)topt->header;
@@ -3352,25 +3361,20 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
cls= GetListOption(g,"class", topt->oplist);
#endif // WIN32
mxr= atoi(GetListOption(g,"maxerr", topt->oplist, "0"));
- } // endif option_list
+ } else {
+ host= "localhost";
+ user= "root";
+ } // endif option_list
if (!db)
db= thd->db; // Default value
// Check table type
if (ttp == TAB_UNDEF) {
- if (!tab) {
- strcpy(g->Message, "No table_type. Was set to DOS");
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0, g->Message);
- ttp= TAB_DOS;
- topt->type= "DOS";
- } else {
- strcpy(g->Message, "No table_type. Was set to PROXY");
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0, g->Message);
- ttp= TAB_PRX;
- topt->type= "PROXY";
- } // endif fnc
-
+ topt->type= (src) ? "MYSQL" : (tab) ? "PROXY" : "DOS";
+ ttp= GetTypeID(topt->type);
+ sprintf(g->Message, "No table_type. Was set to %s", topt->type);
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0, g->Message);
} else if (ttp == TAB_NIY) {
sprintf(g->Message, "Unsupported table type %s", topt->type);
my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
@@ -3494,7 +3498,9 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
else
return HA_ERR_INTERNAL_ERROR; // Should never happen
- switch (ttp) {
+ if (src && fnc == FNC_NO)
+ qrp= SrcColumns(g, host, db, user, pwd, src, port);
+ else switch (ttp) {
case TAB_DBF:
qrp= DBFColumns(g, fn, fnc == FNC_COL);
break;
@@ -3523,7 +3529,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
#if defined(MYSQL_SUPPORT)
case TAB_MYSQL:
qrp= MyColumns(g, host, db, user, pwd, tab,
- NULL, port, false, fnc == FNC_COL);
+ NULL, port, fnc == FNC_COL);
break;
#endif // MYSQL_SUPPORT
case TAB_CSV:
@@ -3549,7 +3555,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
return HA_ERR_INTERNAL_ERROR;
} // endif qrp
- if (fnc != FNC_NO) {
+ if (fnc != FNC_NO || src) {
// Catalog table
for (crp=qrp->Colresp; !b && crp; crp= crp->Next) {
cnm= encode(g, crp->Name);
@@ -3821,13 +3827,23 @@ int ha_connect::create(const char *name, TABLE *table_arg,
case TAB_PRX:
case TAB_XCL:
case TAB_OCCUR:
- if (!stricmp(options->tabname, create_info->alias) &&
- (!options->dbname || !stricmp(options->dbname, thd->db))) {
- sprintf(g->Message, "A %s table cannot refer to itself",
- options->type);
+ if (options->srcdef) {
+ strcpy(g->Message, "Cannot check looping reference");
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0, g->Message);
+ } else if (options->tabname) {
+ if (!stricmp(options->tabname, create_info->alias) &&
+ (!options->dbname || !stricmp(options->dbname, thd->db))) {
+ sprintf(g->Message, "A %s table cannot refer to itself",
+ options->type);
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+ } // endif tab
+
+ } else {
+ strcpy(g->Message, "Missing object table name or definition");
my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
- return HA_ERR_INTERNAL_ERROR;
- } // endif tab
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+ } // endif tabname
} // endswitch ttp
diff --git a/storage/connect/myconn.cpp b/storage/connect/myconn.cpp
index fab2af54aa7..5320171beeb 100644
--- a/storage/connect/myconn.cpp
+++ b/storage/connect/myconn.cpp
@@ -66,13 +66,13 @@ extern MYSQL_PLUGIN_IMPORT uint mysqld_port;
/************************************************************************/
/* MyColumns: constructs the result blocks containing all columns */
-/* of a MySQL table that will be retrieved by GetData commands. */
-/* key = TRUE when called from Create Table to get key informations. */
+/* of a MySQL table or view. */
+/* info = TRUE to get catalog column informations. */
/************************************************************************/
PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db,
const char *user, const char *pwd,
const char *table, const char *colpat,
- int port, bool key, bool info)
+ int port, bool info)
{
static int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING, TYPE_INT,
TYPE_STRING, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT,
@@ -124,9 +124,6 @@ PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db,
length[0] = 128;
} // endif info
-//if (!key) // We are not called from Create table
-// ncol--; // No date format column yet
-
/**********************************************************************/
/* Allocate the structures used to refer to the result set. */
/**********************************************************************/
@@ -219,6 +216,7 @@ PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db,
crp->Kdata->SetValue(fld, i);
} // endfor i
+#if 0
if (k > 1) {
// Multicolumn primary key
PVBLK vbp = qrp->Colresp->Next->Next->Next->Next->Kdata;
@@ -228,6 +226,7 @@ PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db,
vbp->SetValue(k, i);
} // endif k
+#endif // 0
/**********************************************************************/
/* Close MySQL connection. */
@@ -240,6 +239,33 @@ PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db,
return qrp;
} // end of MyColumns
+/************************************************************************/
+/* SrcColumns: constructs the result blocks containing all columns */
+/* resulting from an SQL source definition query execution. */
+/************************************************************************/
+PQRYRES SrcColumns(PGLOBAL g, const char *host, const char *db,
+ const char *user, const char *pwd,
+ const char *srcdef, int port)
+ {
+ int w;
+ MYSQLC myc;
+ PQRYRES qrp = NULL;
+
+ if (!port)
+ port = mysqld_port;
+
+ // 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)
+ qrp = myc.GetResult(g);
+
+ myc.Close();
+ return qrp;
+ } // end of SrcColumns
+
/* -------------------------- Class MYSQLC --------------------------- */
/***********************************************************************/
diff --git a/storage/connect/myconn.h b/storage/connect/myconn.h
index 72ce58e70aa..8148630b812 100644
--- a/storage/connect/myconn.h
+++ b/storage/connect/myconn.h
@@ -38,7 +38,11 @@ typedef class MYSQLC *PMYC;
PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db,
const char *user, const char *pwd,
const char *table, const char *colpat,
- int port, bool key, bool info);
+ int port, bool info);
+
+PQRYRES SrcColumns(PGLOBAL g, const char *host, const char *db,
+ const char *user, const char *pwd,
+ const char *srcdef, int port);
/* -------------------------- MYCONN class --------------------------- */
@@ -47,6 +51,7 @@ PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db,
/***********************************************************************/
class DllItem MYSQLC {
friend class TDBMYSQL;
+ friend class MYSQLCOL;
// Construction
public:
MYSQLC(void);
diff --git a/storage/connect/mysql-test/connect/r/fmt.result b/storage/connect/mysql-test/connect/r/fmt.result
index dc3b42b2231..0be10f69bfd 100644
--- a/storage/connect/mysql-test/connect/r/fmt.result
+++ b/storage/connect/mysql-test/connect/r/fmt.result
@@ -18,7 +18,7 @@ CREATE TABLE t1
id INT NOT NULL field_format=' %n%d%n'
) ENGINE=CONNECT TABLE_TYPE=FMT FILE_NAME='t1.txt';
INSERT INTO t1 VALUES (10),(20);
-ERROR HY000: Got error 122 'Writing FMT files is not implemented yet' from CONNECT
+ERROR HY000: Got error 174 'Writing FMT files is not implemented yet' from CONNECT
DROP TABLE t1;
#
# Testing manual examples
@@ -59,7 +59,7 @@ ID NAME DEPNO SALARY
56 POIROT-DELMOTTE 0 18009.00
345 67 19000.25
UPDATE t1 SET SALARY=1234;
-ERROR HY000: Got error 122 'Writing FMT files is not implemented yet' from CONNECT
+ERROR HY000: Got error 174 'Writing FMT files is not implemented yet' from CONNECT
DELETE FROM t1 WHERE ID=56;
SELECT * FROM t1;
ID NAME DEPNO SALARY
diff --git a/storage/connect/mysql-test/connect/r/pivot.result b/storage/connect/mysql-test/connect/r/pivot.result
index 4480788332b..1b790662c4b 100644
--- a/storage/connect/mysql-test/connect/r/pivot.result
+++ b/storage/connect/mysql-test/connect/r/pivot.result
@@ -77,8 +77,8 @@ Beer DOUBLE(8,2) FLAG=1,
Car DOUBLE(8,2) FLAG=1,
Food DOUBLE(8,2) FLAG=1)
ENGINE=CONNECT TABLE_TYPE=PIVOT
-SRCDEF='select who, week, what, sum(amount) from expenses where week in (4,5) group by who, week, what';
-ALTER TABLE pivex OPTION_LIST='port=PORT';
+SRCDEF='select who, week, what, sum(amount) as amount from expenses where week in (4,5) group by who, week, what';
+ALTER TABLE pivex OPTION_LIST='PivotCol=what,FncCol=amount,port=PORT';
Warnings:
Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk
SELECT * FROM pivex;
@@ -125,7 +125,7 @@ Middle DOUBLE(8,2) FLAG=1,
Last DOUBLE(8,2) FLAG=1)
ENGINE=CONNECT TABLE_TYPE=PIVOT
SRCDEF='select who, what, case when week=3 then ''First'' when week=5 then ''Last'' else ''Middle'' end as wk, sum(amount) * 6.56 as amnt from expenses group by who, what, wk';
-ALTER TABLE pivex OPTION_LIST='PivotCol=wk,port=PORT';
+ALTER TABLE pivex OPTION_LIST='PivotCol=wk,FncCol=amnt,port=PORT';
Warnings:
Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk
SELECT * FROM pivex;
diff --git a/storage/connect/mysql-test/connect/t/fmt.test b/storage/connect/mysql-test/connect/t/fmt.test
index de7f8c06c1b..662bc70c8b1 100644
--- a/storage/connect/mysql-test/connect/t/fmt.test
+++ b/storage/connect/mysql-test/connect/t/fmt.test
@@ -1,85 +1,85 @@
-let $MYSQLD_DATADIR= `select @@datadir`;
---copy_file $MTR_SUITE_DIR/std_data/funny.txt $MYSQLD_DATADIR/test/funny.txt
---copy_file $MTR_SUITE_DIR/std_data/funny2.txt $MYSQLD_DATADIR/test/funny2.txt
-
---echo #
---echo # Testing errors
---echo #
-CREATE TABLE t1
-(
- ID INT NOT NULL field_format=' %n%d%n'
-) Engine=CONNECT table_type=FMT file_name='nonexistent.txt';
---replace_regex /on .*test.nonexistent.txt/on DATADIR\/test\/nonexistent.txt/
-# TODO: check why this is needed for Windows
---replace_result Open(rt) Open(rb)
-SELECT * FROM t1;
-DROP TABLE t1;
-
-
---echo #
---echo # Testing update on FMT tables
---echo #
-CREATE TABLE t1
-(
- id INT NOT NULL field_format=' %n%d%n'
-) ENGINE=CONNECT TABLE_TYPE=FMT FILE_NAME='t1.txt';
---error ER_GET_ERRMSG
-INSERT INTO t1 VALUES (10),(20);
-# TODO:
-#--error ER_GET_ERRMSG
-#UPDATE t1 SET id=20;
-#TRUNCATE TABLE t1;
-#DELETE FROM t1 WHERE id=10;
-#SELECT * FROM t1;
-DROP TABLE t1;
---remove_file $MYSQLD_DATADIR/test/t1.txt
-
-
---echo #
---echo # Testing manual examples
---echo #
-CREATE TABLE t1
-(
- ID Integer(5) not null field_format=' %n%d%n',
- NAME Char(16) not null field_format=" , '%n%[^']%n'",
- DEPNO Integer(4) not null field_format=' , #%n%d%n',
- SALARY Double(12,2) not null field_format=' ; %n%f%n'
-) Engine=CONNECT table_type=FMT file_name='funny.txt';
-SELECT * FROM t1;
-DROP TABLE t1;
-
-#
-# TODO: shoudn't a warning instead of error be returned on bad format?
-#
-CREATE TABLE t1
-(
- ID Integer(5) not null field_format=' %n%d%n',
- NAME Char(16) not null field_format=" , '%n%[^']%n'",
- DEPNO Integer(4) not null field_format=' , #%n%d%n',
- SALARY Double(12,2) not null field_format=' ; %n%f%n'
-) Engine=CONNECT table_type=FMT file_name='funny2.txt';
---error ER_GET_ERRMSG
-SELECT * FROM t1;
-DROP TABLE t1;
-
-CREATE TABLE t1
-(
- ID Integer(5) not null field_format=' %n%d%n',
- NAME Char(16) not null field_format=' , ''%n%[^'']%m',
- DEPNO Integer(4) not null field_format=''' , #%n%d%m',
- SALARY Double(12,2) not null field_format=' ; %n%f%n'
-) Engine=CONNECT table_type=FMT file_name='funny2.txt';
-SELECT * FROM t1;
---error ER_GET_ERRMSG
-UPDATE t1 SET SALARY=1234;
-# TODO: this query crashes
-# UPDATE t1 SET SALARY=1234 WHERE ID=56;
-DELETE FROM t1 WHERE ID=56;
-SELECT * FROM t1;
-DROP TABLE t1;
-
-#
-# Clean up
-#
---remove_file $MYSQLD_DATADIR/test/funny.txt
---remove_file $MYSQLD_DATADIR/test/funny2.txt
+let $MYSQLD_DATADIR= `select @@datadir`;
+--copy_file $MTR_SUITE_DIR/std_data/funny.txt $MYSQLD_DATADIR/test/funny.txt
+--copy_file $MTR_SUITE_DIR/std_data/funny2.txt $MYSQLD_DATADIR/test/funny2.txt
+
+--echo #
+--echo # Testing errors
+--echo #
+CREATE TABLE t1
+(
+ ID INT NOT NULL field_format=' %n%d%n'
+) Engine=CONNECT table_type=FMT file_name='nonexistent.txt';
+--replace_regex /on .*test.nonexistent.txt/on DATADIR\/test\/nonexistent.txt/
+# TODO: check why this is needed for Windows
+--replace_result Open(rt) Open(rb)
+SELECT * FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Testing update on FMT tables
+--echo #
+CREATE TABLE t1
+(
+ id INT NOT NULL field_format=' %n%d%n'
+) ENGINE=CONNECT TABLE_TYPE=FMT FILE_NAME='t1.txt';
+--error ER_GET_ERRMSG
+INSERT INTO t1 VALUES (10),(20);
+# TODO:
+#--error ER_GET_ERRMSG
+#UPDATE t1 SET id=20;
+#TRUNCATE TABLE t1;
+#DELETE FROM t1 WHERE id=10;
+#SELECT * FROM t1;
+DROP TABLE t1;
+#--remove_file $MYSQLD_DATADIR/test/t1.txt
+
+
+--echo #
+--echo # Testing manual examples
+--echo #
+CREATE TABLE t1
+(
+ ID Integer(5) not null field_format=' %n%d%n',
+ NAME Char(16) not null field_format=" , '%n%[^']%n'",
+ DEPNO Integer(4) not null field_format=' , #%n%d%n',
+ SALARY Double(12,2) not null field_format=' ; %n%f%n'
+) Engine=CONNECT table_type=FMT file_name='funny.txt';
+SELECT * FROM t1;
+DROP TABLE t1;
+
+#
+# TODO: shoudn't a warning instead of error be returned on bad format?
+#
+CREATE TABLE t1
+(
+ ID Integer(5) not null field_format=' %n%d%n',
+ NAME Char(16) not null field_format=" , '%n%[^']%n'",
+ DEPNO Integer(4) not null field_format=' , #%n%d%n',
+ SALARY Double(12,2) not null field_format=' ; %n%f%n'
+) Engine=CONNECT table_type=FMT file_name='funny2.txt';
+--error ER_GET_ERRMSG
+SELECT * FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1
+(
+ ID Integer(5) not null field_format=' %n%d%n',
+ NAME Char(16) not null field_format=' , ''%n%[^'']%m',
+ DEPNO Integer(4) not null field_format=''' , #%n%d%m',
+ SALARY Double(12,2) not null field_format=' ; %n%f%n'
+) Engine=CONNECT table_type=FMT file_name='funny2.txt';
+SELECT * FROM t1;
+--error ER_GET_ERRMSG
+UPDATE t1 SET SALARY=1234;
+# TODO: this query crashes
+# UPDATE t1 SET SALARY=1234 WHERE ID=56;
+DELETE FROM t1 WHERE ID=56;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+#
+# Clean up
+#
+--remove_file $MYSQLD_DATADIR/test/funny.txt
+--remove_file $MYSQLD_DATADIR/test/funny2.txt
diff --git a/storage/connect/mysql-test/connect/t/pivot.test b/storage/connect/mysql-test/connect/t/pivot.test
index f06c92828f9..87601a26d28 100644
--- a/storage/connect/mysql-test/connect/t/pivot.test
+++ b/storage/connect/mysql-test/connect/t/pivot.test
@@ -1,144 +1,145 @@
-let $MYSQLD_DATADIR= `select @@datadir`;
-let $PORT= `select @@port`;
---copy_file $MTR_SUITE_DIR/std_data/expenses.txt $MYSQLD_DATADIR/test/expenses.txt
-
---echo #
---echo # Testing the PIVOT table type
---echo #
-CREATE TABLE expenses (
-Who CHAR(10) NOT NULL,
-Week INT(2) NOT NULL,
-What CHAR(12) NOT NULL,
-Amount DOUBLE(8,2))
-ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='expenses.txt' ENDING=2;
-SELECT * FROM expenses;
-
---echo #
---echo # Pivoting from What
---echo #
-CREATE TABLE pivex (
-Who CHAR(10) NOT NULL,
-Week INT(2) NOT NULL,
-Beer DOUBLE(8,2) FLAG=1,
-Car DOUBLE(8,2) FLAG=1,
-Food DOUBLE(8,2) FLAG=1)
-ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=expenses;
---replace_result $PORT PORT
---eval ALTER TABLE pivex OPTION_LIST='port=$PORT'
-SELECT * FROM pivex;
-
---echo #
---echo # Restricting the columns in a Pivot Table
---echo #
-ALTER TABLE pivex DROP COLUMN week;
-SELECT * FROM pivex;
-
---echo #
---echo # Using a source definition
---echo #
-DROP TABLE pivex;
-CREATE TABLE pivex (
-Who CHAR(10) NOT NULL,
-Week INT(2) NOT NULL,
-Beer DOUBLE(8,2) FLAG=1,
-Car DOUBLE(8,2) FLAG=1,
-Food DOUBLE(8,2) FLAG=1)
-ENGINE=CONNECT TABLE_TYPE=PIVOT
-SRCDEF='select who, week, what, sum(amount) from expenses where week in (4,5) group by who, week, what';
---replace_result $PORT PORT
---eval ALTER TABLE pivex OPTION_LIST='port=$PORT'
-SELECT * FROM pivex;
-
---echo #
---echo # Pivoting from Week
---echo #
-DROP TABLE pivex;
-CREATE TABLE pivex (
-Who CHAR(10) NOT NULL,
-What CHAR(12) NOT NULL,
-`3` DOUBLE(8,2) FLAG=1,
-`4` DOUBLE(8,2) FLAG=1,
-`5` DOUBLE(8,2) FLAG=1)
-ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=expenses;
---replace_result $PORT PORT
---eval ALTER TABLE pivex OPTION_LIST='PivotCol=Week,port=$PORT'
-SELECT * FROM pivex;
-
---echo #
---echo # Using scalar functions and expresssions
---echo #
-DROP TABLE pivex;
-CREATE TABLE pivex (
-Who CHAR(10) NOT NULL,
-What CHAR(12) NOT NULL,
-First DOUBLE(8,2) FLAG=1,
-Middle DOUBLE(8,2) FLAG=1,
-Last DOUBLE(8,2) FLAG=1)
-ENGINE=CONNECT TABLE_TYPE=PIVOT
-SRCDEF='select who, what, case when week=3 then ''First'' when week=5 then ''Last'' else ''Middle'' end as wk, sum(amount) * 6.56 as amnt from expenses group by who, what, wk';
---replace_result $PORT PORT
---eval ALTER TABLE pivex OPTION_LIST='PivotCol=wk,port=$PORT'
-SELECT * FROM pivex;
-DROP TABLE pivex;
-DROP TABLE expenses;
-
---echo #
---echo # Make the PETS table
---echo #
-CREATE TABLE pets (
-Name VARCHAR(12) NOT NULL,
-Race CHAR(6) NOT NULL,
-Number INT NOT NULL) ENGINE=MYISAM;
-INSERT INTO pets VALUES('John','dog',2);
-INSERT INTO pets VALUES('Bill','cat',1);
-INSERT INTO pets VALUES('Mary','dog',1);
-INSERT INTO pets VALUES('Mary','cat',1);
-INSERT INTO pets VALUES('Lisbeth','rabbit',2);
-INSERT INTO pets VALUES('Kevin','cat',2);
-INSERT INTO pets VALUES('Kevin','bird',6);
-INSERT INTO pets VALUES('Donald','dog',1);
-INSERT INTO pets VALUES('Donald','fish',3);
-SELECT * FROM pets;
-
---echo #
---echo # Pivot the PETS table
---echo #
-CREATE TABLE pivet (
-name VARCHAR(12) NOT NULL,
-dog INT NOT NULL DEFAULT 0 FLAG=1,
-cat INT NOT NULL DEFAULT 0 FLAG=1,
-rabbit INT NOT NULL DEFAULT 0 FLAG=1,
-bird INT NOT NULL DEFAULT 0 FLAG=1,
-fish INT NOT NULL DEFAULT 0 FLAG=1)
-ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=pets OPTION_LIST='PivotCol=race,groupby=1';
-SELECT * FROM pivet;
-DROP TABLE pivet;
-
---echo #
---echo # Testing the "data" column list
---echo #
-CREATE TABLE pivet (
-name VARCHAR(12) NOT NULL,
-dog INT NOT NULL DEFAULT 0 FLAG=1,
-cat INT NOT NULL DEFAULT 0 FLAG=1)
-ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=pets OPTION_LIST='PivotCol=race,groupby=1';
---error ER_GET_ERRMSG
-SELECT * FROM pivet;
-ALTER TABLE pivet OPTION_LIST='PivotCol=race,groupby=1,accept=1';
-SELECT * FROM pivet;
-DROP TABLE pivet;
-
---echo #
---echo # Adding a "dump" column
---echo #
-CREATE TABLE pivet (
-name VARCHAR(12) NOT NULL,
-dog INT NOT NULL DEFAULT 0 FLAG=1,
-cat INT NOT NULL DEFAULT 0 FLAG=1,
-other INT NOT NULL DEFAULT 0 FLAG=2)
-ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=pets OPTION_LIST='PivotCol=race,groupby=1';
-SELECT * FROM pivet;
-
-DROP TABLE pivet;
-DROP TABLE pets;
---remove_file $MYSQLD_DATADIR/test/expenses.txt
+let $MYSQLD_DATADIR= `select @@datadir`;
+let $PORT= `select @@port`;
+--copy_file $MTR_SUITE_DIR/std_data/expenses.txt $MYSQLD_DATADIR/test/expenses.txt
+--copy_file $MTR_SUITE_DIR/std_data/connect.ini $MYSQLD_DATADIR/test/connect.ini
+
+--echo #
+--echo # Testing the PIVOT table type
+--echo #
+CREATE TABLE expenses (
+Who CHAR(10) NOT NULL,
+Week INT(2) NOT NULL,
+What CHAR(12) NOT NULL,
+Amount DOUBLE(8,2))
+ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='expenses.txt' ENDING=2;
+SELECT * FROM expenses;
+
+--echo #
+--echo # Pivoting from What
+--echo #
+CREATE TABLE pivex (
+Who CHAR(10) NOT NULL,
+Week INT(2) NOT NULL,
+Beer DOUBLE(8,2) FLAG=1,
+Car DOUBLE(8,2) FLAG=1,
+Food DOUBLE(8,2) FLAG=1)
+ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=expenses;
+--replace_result $PORT PORT
+--eval ALTER TABLE pivex OPTION_LIST='port=$PORT'
+SELECT * FROM pivex;
+
+--echo #
+--echo # Restricting the columns in a Pivot Table
+--echo #
+ALTER TABLE pivex DROP COLUMN week;
+SELECT * FROM pivex;
+
+--echo #
+--echo # Using a source definition
+--echo #
+DROP TABLE pivex;
+CREATE TABLE pivex (
+Who CHAR(10) NOT NULL,
+Week INT(2) NOT NULL,
+Beer DOUBLE(8,2) FLAG=1,
+Car DOUBLE(8,2) FLAG=1,
+Food DOUBLE(8,2) FLAG=1)
+ENGINE=CONNECT TABLE_TYPE=PIVOT
+SRCDEF='select who, week, what, sum(amount) as amount from expenses where week in (4,5) group by who, week, what';
+--replace_result $PORT PORT
+--eval ALTER TABLE pivex OPTION_LIST='PivotCol=what,FncCol=amount,port=$PORT'
+SELECT * FROM pivex;
+
+--echo #
+--echo # Pivoting from Week
+--echo #
+DROP TABLE pivex;
+CREATE TABLE pivex (
+Who CHAR(10) NOT NULL,
+What CHAR(12) NOT NULL,
+`3` DOUBLE(8,2) FLAG=1,
+`4` DOUBLE(8,2) FLAG=1,
+`5` DOUBLE(8,2) FLAG=1)
+ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=expenses;
+--replace_result $PORT PORT
+--eval ALTER TABLE pivex OPTION_LIST='PivotCol=Week,port=$PORT'
+SELECT * FROM pivex;
+
+--echo #
+--echo # Using scalar functions and expresssions
+--echo #
+DROP TABLE pivex;
+CREATE TABLE pivex (
+Who CHAR(10) NOT NULL,
+What CHAR(12) NOT NULL,
+First DOUBLE(8,2) FLAG=1,
+Middle DOUBLE(8,2) FLAG=1,
+Last DOUBLE(8,2) FLAG=1)
+ENGINE=CONNECT TABLE_TYPE=PIVOT
+SRCDEF='select who, what, case when week=3 then ''First'' when week=5 then ''Last'' else ''Middle'' end as wk, sum(amount) * 6.56 as amnt from expenses group by who, what, wk';
+--replace_result $PORT PORT
+--eval ALTER TABLE pivex OPTION_LIST='PivotCol=wk,FncCol=amnt,port=$PORT'
+SELECT * FROM pivex;
+DROP TABLE pivex;
+DROP TABLE expenses;
+
+--echo #
+--echo # Make the PETS table
+--echo #
+CREATE TABLE pets (
+Name VARCHAR(12) NOT NULL,
+Race CHAR(6) NOT NULL,
+Number INT NOT NULL) ENGINE=MYISAM;
+INSERT INTO pets VALUES('John','dog',2);
+INSERT INTO pets VALUES('Bill','cat',1);
+INSERT INTO pets VALUES('Mary','dog',1);
+INSERT INTO pets VALUES('Mary','cat',1);
+INSERT INTO pets VALUES('Lisbeth','rabbit',2);
+INSERT INTO pets VALUES('Kevin','cat',2);
+INSERT INTO pets VALUES('Kevin','bird',6);
+INSERT INTO pets VALUES('Donald','dog',1);
+INSERT INTO pets VALUES('Donald','fish',3);
+SELECT * FROM pets;
+
+--echo #
+--echo # Pivot the PETS table
+--echo #
+CREATE TABLE pivet (
+name VARCHAR(12) NOT NULL,
+dog INT NOT NULL DEFAULT 0 FLAG=1,
+cat INT NOT NULL DEFAULT 0 FLAG=1,
+rabbit INT NOT NULL DEFAULT 0 FLAG=1,
+bird INT NOT NULL DEFAULT 0 FLAG=1,
+fish INT NOT NULL DEFAULT 0 FLAG=1)
+ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=pets OPTION_LIST='PivotCol=race,groupby=1';
+SELECT * FROM pivet;
+DROP TABLE pivet;
+
+--echo #
+--echo # Testing the "data" column list
+--echo #
+CREATE TABLE pivet (
+name VARCHAR(12) NOT NULL,
+dog INT NOT NULL DEFAULT 0 FLAG=1,
+cat INT NOT NULL DEFAULT 0 FLAG=1)
+ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=pets OPTION_LIST='PivotCol=race,groupby=1';
+--error ER_GET_ERRMSG
+SELECT * FROM pivet;
+ALTER TABLE pivet OPTION_LIST='PivotCol=race,groupby=1,accept=1';
+SELECT * FROM pivet;
+DROP TABLE pivet;
+
+--echo #
+--echo # Adding a "dump" column
+--echo #
+CREATE TABLE pivet (
+name VARCHAR(12) NOT NULL,
+dog INT NOT NULL DEFAULT 0 FLAG=1,
+cat INT NOT NULL DEFAULT 0 FLAG=1,
+other INT NOT NULL DEFAULT 0 FLAG=2)
+ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=pets OPTION_LIST='PivotCol=race,groupby=1';
+SELECT * FROM pivet;
+
+DROP TABLE pivet;
+DROP TABLE pets;
+--remove_file $MYSQLD_DATADIR/test/expenses.txt
diff --git a/storage/connect/plgdbsem.h b/storage/connect/plgdbsem.h
index 5eb55c4a29b..6884c1c4176 100644
--- a/storage/connect/plgdbsem.h
+++ b/storage/connect/plgdbsem.h
@@ -24,8 +24,8 @@
#define DOS_BUFF_LEN 100 /* Number of lines in binary file buffer */
#undef DOMAIN /* For Unix version */
-enum BLKTYP {TYPE_TABLE = 50, /* Table Name/Correl Block */
- TYPE_COLUMN = 51, /* Column Name/Correl Block */
+enum BLKTYP {TYPE_TABLE = 50, /* Table Name/Srcdef/... Block */
+ TYPE_COLUMN = 51, /* Column Name/Qualifier Block */
// TYPE_OPVAL = 52, /* Operator value (OPVAL) */
TYPE_TDB = 53, /* Table Description Block */
TYPE_COLBLK = 54, /* Column Description Block */
diff --git a/storage/connect/plugutil.c b/storage/connect/plugutil.c
index 693ae96cf52..426401a0c47 100644
--- a/storage/connect/plugutil.c
+++ b/storage/connect/plugutil.c
@@ -147,6 +147,7 @@ PGLOBAL PlugInit(LPCSTR Language, uint worksize)
if (!(g = malloc(sizeof(GLOBAL)))) {
fprintf(stderr, MSG(GLOBAL_ERROR), (int)sizeof(GLOBAL));
+ return NULL;
} else {
g->Sarea_Size = worksize;
g->Trace = 0;
@@ -180,7 +181,9 @@ int PlugExit(PGLOBAL g)
if (!g)
return rc;
- free(g->Sarea);
+ if (g->Sarea)
+ free(g->Sarea);
+
free(g);
return rc;
} /* end of PlugExit */
diff --git a/storage/connect/tabcol.cpp b/storage/connect/tabcol.cpp
index f0e010291c3..9af52043f0c 100644
--- a/storage/connect/tabcol.cpp
+++ b/storage/connect/tabcol.cpp
@@ -1,7 +1,7 @@
/************* TabCol C++ Functions Source Code File (.CPP) ************/
-/* Name: TABCOL.CPP Version 2.6 */
+/* Name: TABCOL.CPP Version 2.7 */
/* */
-/* (C) Copyright to the author Olivier BERTRAND 1998-2012 */
+/* (C) Copyright to the author Olivier BERTRAND 1998-2013 */
/* */
/* This file contains the PlugDB++ XTAB, COLUMN and XORDER methods. */
/***********************************************************************/
@@ -23,18 +23,18 @@
#include "tabcol.h"
/***********************************************************************/
-/* XTAB public constructor (in which Correl defaults to Name). */
+/* XTAB public constructor. */
/***********************************************************************/
-XTAB::XTAB(LPCSTR name, LPCSTR correl) : Name(name)
+XTAB::XTAB(LPCSTR name, LPCSTR srcdef) : Name(name)
{
Next = NULL;
To_Tdb = NULL;
- Correl = (correl) ? correl : name;
+ Srcdef = srcdef;
Creator = NULL;
Qualifier = NULL;
#ifdef DEBTRACE
- htrc(" making new TABLE %s %s\n", Name, Correl);
+ htrc(" making new TABLE %s %s\n", Name, Srcdef);
#endif
} // end of XTAB constructor
@@ -45,12 +45,12 @@ XTAB::XTAB(PTABLE tp) : Name(tp->Name)
{
Next = NULL;
To_Tdb = NULL;
- Correl = tp->Correl;
+ Srcdef = tp->Srcdef;
Creator = tp->Creator;
Qualifier = tp->Qualifier;
#ifdef DEBTRACE
- htrc(" making copy TABLE %s %s\n", Name, Correl);
+ htrc(" making copy TABLE %s %s\n", Name, Srcdef);
#endif
} // end of XTAB constructor
@@ -83,7 +83,7 @@ void XTAB::Print(PGLOBAL g, FILE *f, uint n)
for (PTABLE tp = this; tp; tp = tp->Next) {
fprintf(f, "%sTABLE: %s.%s %s\n",
- m, SVP(tp->Creator), tp->Name, SVP(tp->Correl));
+ m, SVP(tp->Creator), tp->Name, SVP(tp->Srcdef));
PlugPutOut(g, f, TYPE_TDB, tp->To_Tdb, n + 2);
} /* endfor tp */
@@ -101,7 +101,7 @@ void XTAB::Print(PGLOBAL g, char *ps, uint z)
for (PTABLE tp = this; tp && n > 0; tp = tp->Next) {
i = sprintf(buf, "TABLE: %s.%s %s To_Tdb=%p ",
- SVP(tp->Creator), tp->Name, SVP(tp->Correl), tp->To_Tdb);
+ SVP(tp->Creator), tp->Name, SVP(tp->Srcdef), tp->To_Tdb);
strncat(ps, buf, n);
n -= i;
} // endif tp
diff --git a/storage/connect/tabcol.h b/storage/connect/tabcol.h
index 4680e50f29e..20e23b80225 100644
--- a/storage/connect/tabcol.h
+++ b/storage/connect/tabcol.h
@@ -1,7 +1,7 @@
/*************** TabCol H Declares Source Code File (.H) ***************/
-/* Name: TABCOL.H Version 2.7 */
+/* Name: TABCOL.H Version 2.8 */
/* */
-/* (C) Copyright to the author Olivier BERTRAND 1998-2012 */
+/* (C) Copyright to the author Olivier BERTRAND 1998-2013 */
/* */
/* This file contains the XTAB, COLUMN and XORDER class definitions. */
/***********************************************************************/
@@ -15,23 +15,23 @@
/***********************************************************************/
/* Definition of class XTAB with all its method functions. */
/***********************************************************************/
-class DllExport XTAB: public BLOCK { // Table Name-Owner-Correl block.
+class DllExport XTAB: public BLOCK { // Table Name-Owner-Srcdef block.
friend class TDBPRX;
public:
// Constructors
- XTAB(LPCSTR name, LPCSTR correl = NULL);
+ XTAB(LPCSTR name, LPCSTR srcdef = NULL);
XTAB(PTABLE tp);
// Implementation
PTABLE GetNext(void) {return Next;}
PTDB GetTo_Tdb(void) {return To_Tdb;}
LPCSTR GetName(void) {return Name;}
- LPCSTR GetCorrel(void) {return Correl;}
+ LPCSTR GetSrc(void) {return Srcdef;}
LPCSTR GetCreator(void) {return Creator;}
LPCSTR GetQualifier(void) {return Qualifier;}
void SetTo_Tdb(PTDB tdbp) {To_Tdb = tdbp;}
void SetName(LPCSTR name) {Name = name;}
- void SetCorrel(LPCSTR correl) {Correl = correl;}
+ void SetSrc(LPCSTR srcdef) {Srcdef = srcdef;}
void SetCreator(LPCSTR crname) {Creator = crname;}
void SetQualifier(LPCSTR qname) {Qualifier = qname;}
@@ -44,8 +44,8 @@ class DllExport XTAB: public BLOCK { // Table Name-Owner-Correl block.
// Members
PTABLE Next; // Points to next table in chain
PTDB To_Tdb; // Points to Table description Block
- LPCSTR Name; // Table name (can be changed by LNA and PLG)
- LPCSTR Correl; // Correlation name
+ LPCSTR Name; // Table name
+ LPCSTR Srcdef; // Table Source definition
LPCSTR Creator; // Creator name
LPCSTR Qualifier; // Qualifier name
}; // end of class XTAB
diff --git a/storage/connect/tabfmt.cpp b/storage/connect/tabfmt.cpp
index aaa32a57f04..860a1304a14 100644
--- a/storage/connect/tabfmt.cpp
+++ b/storage/connect/tabfmt.cpp
@@ -1088,7 +1088,12 @@ bool TDBFMT::OpenDB(PGLOBAL g)
{
Linenum = 0;
- if (Use != USE_OPEN && (Columns || Mode == MODE_UPDATE)) {
+ if (Mode == MODE_INSERT || Mode == MODE_UPDATE) {
+ sprintf(g->Message, MSG(FMT_WRITE_NIY), "FMT");
+ return true; // NIY
+ } // endif Mode
+
+ if (Use != USE_OPEN && Columns) {
// Make the formats used to read records
PSZ pfm;
int i, n;
@@ -1096,17 +1101,12 @@ bool TDBFMT::OpenDB(PGLOBAL g)
PCOLDEF cdp;
PDOSDEF tdp = (PDOSDEF)To_Def;
-// if (Mode != MODE_UPDATE) {
- for (colp = (PCSVCOL)Columns; colp; colp = (PCSVCOL)colp->Next)
- if (!colp->IsSpecial()) // Not a pseudo column
- Fields = max(Fields, (int)colp->Fldnum);
-
- if (Columns)
- Fields++; // Fldnum was 0 based
+ for (colp = (PCSVCOL)Columns; colp; colp = (PCSVCOL)colp->Next)
+ if (!colp->IsSpecial()) // Not a pseudo column
+ Fields = max(Fields, (int)colp->Fldnum);
-// } else
-// for (cdp = tdp->GetCols(); cdp; cdp = cdp->GetNext())
-// Fields++;
+ if (Columns)
+ Fields++; // Fldnum was 0 based
To_Fld = PlugSubAlloc(g, NULL, Lrecl + 1);
FldFormat = (PSZ*)PlugSubAlloc(g, NULL, sizeof(PSZ) * Fields);
diff --git a/storage/connect/tabmysql.cpp b/storage/connect/tabmysql.cpp
index 3ecfd6aa6c1..c9bb47792f5 100644
--- a/storage/connect/tabmysql.cpp
+++ b/storage/connect/tabmysql.cpp
@@ -79,9 +79,11 @@ MYSQLDEF::MYSQLDEF(void)
Hostname = NULL;
Database = NULL;
Tabname = NULL;
+ Srcdef = NULL;
Username = NULL;
Password = NULL;
Portnumber = 0;
+ Isview = FALSE;
Bind = FALSE;
Delayed = FALSE;
} // end of MYSQLDEF constructor
@@ -302,8 +304,8 @@ bool MYSQLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
} else {
// MYSQL access from a PROXY table, not using URL
Database = Cat->GetStringCatInfo(g, "Database", "*");
- Tabname = Cat->GetStringCatInfo(g, "Name", Name); // Deprecated
- Tabname = Cat->GetStringCatInfo(g, "Tabname", Tabname);
+ Tabname = Name;
+ Isview = Cat->GetBoolCatInfo("View", FALSE);
// We must get connection parms from the calling table
Remove_tshp(Cat);
@@ -313,6 +315,9 @@ bool MYSQLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
Portnumber = Cat->GetIntCatInfo("Port", mysqld_port);
} // endif am
+ if ((Srcdef = Cat->GetStringCatInfo(g, "Srcdef", NULL)))
+ Isview = TRUE;
+
return FALSE;
} // end of DefineAM
@@ -339,18 +344,22 @@ TDBMYSQL::TDBMYSQL(PMYDEF tdp) : TDBASE(tdp)
Host = tdp->GetHostname();
Database = tdp->GetDatabase();
Tabname = tdp->GetTabname();
+ Srcdef = tdp->GetSrcdef();
User = tdp->GetUsername();
Pwd = tdp->GetPassword();
Port = tdp->GetPortnumber();
+ Isview = tdp->Isview;
Prep = tdp->Bind;
Delayed = tdp->Delayed;
} else {
Host = NULL;
Database = NULL;
Tabname = NULL;
+ Srcdef = NULL;
User = NULL;
Pwd = NULL;
Port = 0;
+ Isview = FALSE;
Prep = FALSE;
Delayed = FALSE;
} // endif tdp
@@ -370,9 +379,11 @@ TDBMYSQL::TDBMYSQL(PGLOBAL g, PTDBMY tdbp) : TDBASE(tdbp)
Host = tdbp->Host;
Database = tdbp->Database;
Tabname = tdbp->Tabname;
+ Srcdef = tdbp->Srcdef;
User = tdbp->User;
Pwd = tdbp->Pwd;
Port = tdbp->Port;
+ Isview = tdbp->Isview;
Prep = tdbp->Prep;
Delayed = tdbp->Delayed;
Bind = NULL;
@@ -418,55 +429,54 @@ PCOL TDBMYSQL::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
/***********************************************************************/
bool TDBMYSQL::MakeSelect(PGLOBAL g)
{
- char *colist;
char *tk = "`";
- int len = 0, ncol = 0, rank = 0;
+ int rank = 0;
bool b = FALSE;
PCOL colp;
- PDBUSER dup = PlgGetUser(g);
+//PDBUSER dup = PlgGetUser(g);
if (Query)
return FALSE; // already done
- for (colp = Columns; colp; colp = colp->GetNext())
- ncol++;
+ if (Srcdef) {
+ Query = Srcdef;
+ return false;
+ } // endif Srcdef
- if (ncol) {
- colist = (char*)PlugSubAlloc(g, NULL, (NAM_LEN + 4) * ncol);
- *colist = '\0';
+ //Find the address of the suballocated query
+ Query = (char*)PlugSubAlloc(g, NULL, 0);
+ strcpy(Query, "SELECT ");
+ if (Columns) {
for (colp = Columns; colp; colp = colp->GetNext())
if (colp->IsSpecial()) {
strcpy(g->Message, MSG(NO_SPEC_COL));
return TRUE;
} else {
if (b)
- strcat(colist, ", ");
+ strcat(Query, ", ");
else
b = TRUE;
- strcat(strcat(strcat(colist, tk), colp->GetName()), tk);
+ strcat(strcat(strcat(Query, tk), colp->GetName()), tk);
((PMYCOL)colp)->Rank = rank++;
} // endif colp
} else {
- // ncol == 0 can occur for queries such as Query count(*) from...
- // for which we will count the rows from Query '*' from...
+ // ncol == 0 can occur for views or queries such as
+ // Query count(*) from... for which we will count the rows from
+ // Query '*' from...
// (the use of a char constant minimize the result storage)
- colist = (char*)PlugSubAlloc(g, NULL, 2);
- strcpy(colist, "'*'");
+ strcat(Query, (Isview) ? "*" : "'*'");
} // endif ncol
- // Below 32 is space to contain extra stuff
- len += (strlen(colist) + strlen(Tabname) + 32);
- len += (To_Filter ? strlen(To_Filter) + 7 : 0);
- Query = (char*)PlugSubAlloc(g, NULL, len);
- strcat(strcpy(Query, "SELECT "), colist);
strcat(strcat(strcat(strcat(Query, " FROM "), tk), Tabname), tk);
if (To_Filter)
strcat(strcat(Query, " WHERE "), To_Filter);
+ // Now we know how much to suballocate
+ PlugSubAlloc(g, NULL, strlen(Query) + 1);
return FALSE;
} // end of MakeSelect
@@ -751,7 +761,7 @@ bool TDBMYSQL::OpenDB(PGLOBAL g)
/* Table already open, just replace it at its beginning. */
/*******************************************************************/
Myc.Rewind();
- return FALSE;
+ return false;
} // endif use
/*********************************************************************/
@@ -763,7 +773,7 @@ bool TDBMYSQL::OpenDB(PGLOBAL g)
/*********************************************************************/
if (!Myc.Connected()) {
if (Myc.Open(g, Host, Database, User, Pwd, Port))
- return TRUE;
+ return true;
} // endif Connected
@@ -774,7 +784,24 @@ bool TDBMYSQL::OpenDB(PGLOBAL g)
if (!MakeSelect(g))
m_Rc = Myc.ExecSQL(g, Query);
+#if 0
+ if (!Myc.m_Res || !Myc.m_Fields) {
+ sprintf(g->Message, "%s result", (Myc.m_Res) ? "Void" : "No");
+ Myc.Close();
+ return true;
+ } // endif m_Res
+#endif // 0
+
+ if (Srcdef)
+ if (SetColumnRanks(g))
+ return true;
+
} else if (Mode == MODE_INSERT) {
+ if (Srcdef) {
+ strcpy(g->Message, "No insert into anonym views");
+ return true;
+ } // endif Srcdef
+
if (!MakeInsert(g)) {
#if defined(MYSQL_PREPARED_STATEMENTS)
int n = (Prep) ? Myc.PrepareSQL(g, Query) : Nparm;
@@ -827,6 +854,55 @@ bool TDBMYSQL::OpenDB(PGLOBAL g)
} // end of OpenDB
/***********************************************************************/
+/* Set the rank of columns in the result set. */
+/***********************************************************************/
+bool TDBMYSQL::SetColumnRanks(PGLOBAL g)
+ {
+ for (PCOL colp = Columns; colp; colp = colp->GetNext())
+ if (((PMYCOL)colp)->FindRank(g))
+ return TRUE;
+
+ return FALSE;
+ } // end of SetColumnRanks
+
+/***********************************************************************/
+/* Called by Parent table to make the columns of a View. */
+/***********************************************************************/
+PCOL TDBMYSQL::MakeFieldColumn(PGLOBAL g, char *name)
+ {
+ int n;
+ MYSQL_FIELD *fld;
+ PCOL cp, colp = NULL;
+
+ for (n = 0; n < Myc.m_Fields; n++) {
+ fld = &Myc.m_Res->fields[n];
+
+ if (!stricmp(name, fld->name)) {
+ colp = new(g) MYSQLCOL(fld, this, n);
+
+ if (colp->InitValue(g))
+ return NULL;
+
+ if (!Columns)
+ Columns = colp;
+ else for (cp = Columns; cp; cp = cp->GetNext())
+ if (!cp->GetNext()) {
+ cp->SetNext(colp);
+ break;
+ } // endif Next
+
+ break;
+ } // endif name
+
+ } // endfor n
+
+ if (!colp)
+ sprintf(g->Message, "Column %s is not in view", name);
+
+ return colp;
+ } // end of MakeFieldColumn
+
+/***********************************************************************/
/* Data Base read routine for MYSQL access method. */
/***********************************************************************/
int TDBMYSQL::ReadDB(PGLOBAL g)
@@ -939,7 +1015,7 @@ MYSQLCOL::MYSQLCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am)
tdbp->SetColumns(this);
} // endif cprec
- // Set additional Dos access method information for column.
+ // Set additional MySQL access method information for column.
Long = cdp->GetLong();
Bind = NULL;
To_Val = NULL;
@@ -952,6 +1028,33 @@ MYSQLCOL::MYSQLCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am)
} // end of MYSQLCOL constructor
/***********************************************************************/
+/* MYSQLCOL public constructor. */
+/***********************************************************************/
+MYSQLCOL::MYSQLCOL(MYSQL_FIELD *fld, PTDB tdbp, int i, PSZ am)
+ : COLBLK(NULL, tdbp, i)
+ {
+ Name = fld->name;
+ Opt = 0;
+ Long = fld->length;
+ Buf_Type = MYSQLtoPLG(fld->type);
+ strcpy(Format.Type, GetFormatType(Buf_Type));
+ Format.Length = Long;
+ Format.Prec = fld->decimals;
+ ColUse = U_P;
+ Nullable = !IS_NOT_NULL(fld->flags);
+
+ // Set additional MySQL access method information for column.
+ Bind = NULL;
+ To_Val = NULL;
+ Slen = 0;
+ Rank = i;
+
+ if (trace)
+ htrc(" making new %sCOL C%d %s at %p\n", am, Index, Name, this);
+
+ } // end of MYSQLCOL constructor
+
+/***********************************************************************/
/* MYSQLCOL constructor used for copying columns. */
/* tdbp is the pointer to the new table descriptor. */
/***********************************************************************/
@@ -965,6 +1068,24 @@ MYSQLCOL::MYSQLCOL(MYSQLCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
} // end of MYSQLCOL copy constructor
/***********************************************************************/
+/* FindRank: Find the rank of this column in the result set. */
+/***********************************************************************/
+bool MYSQLCOL::FindRank(PGLOBAL g)
+{
+ int n;
+ MYSQLC myc = ((PTDBMY)To_Tdb)->Myc;
+
+ for (n = 0; n < myc.m_Fields; n++)
+ if (!stricmp(Name, myc.m_Res->fields[n].name)) {
+ Rank = n;
+ return false;
+ } // endif Name
+
+ sprintf(g->Message, "Column %s not in result set", Name);
+ return true;
+} // end of FindRank
+
+/***********************************************************************/
/* SetBuffer: prepare a column block for write operation. */
/***********************************************************************/
bool MYSQLCOL::SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check)
@@ -1049,11 +1170,6 @@ void MYSQLCOL::ReadColumn(PGLOBAL g)
int rc;
PTDBMY tdbp = (PTDBMY)To_Tdb;
- if (trace)
- htrc("MySQL ReadColumn: name=%s\n", Name);
-
- assert (Rank >= 0);
-
/*********************************************************************/
/* If physical fetching of the line was deferred, do it now. */
/*********************************************************************/
@@ -1066,14 +1182,17 @@ void MYSQLCOL::ReadColumn(PGLOBAL g)
} else
tdbp->Fetched = TRUE;
- if ((buf = ((PTDBMY)To_Tdb)->Myc.GetCharField(Rank)))
+ if ((buf = ((PTDBMY)To_Tdb)->Myc.GetCharField(Rank))) {
+ if (trace)
+ htrc("MySQL ReadColumn: name=%s buf=%s\n", Name, buf);
+
Value->SetValue_char(buf, Long);
- else {
+ } else {
if (Nullable)
Value->SetNull(true);
Value->Reset(); // Null value
- } // endelse
+ } // endif buf
} // end of ReadColumn
@@ -1121,5 +1240,5 @@ TDBMCL::TDBMCL(PMYDEF tdp) : TDBCAT(tdp)
/***********************************************************************/
PQRYRES TDBMCL::GetResult(PGLOBAL g)
{
- return MyColumns(g, Host, Db, User, Pwd, Tab, NULL, Port, false, false);
+ return MyColumns(g, Host, Db, User, Pwd, Tab, NULL, Port, false);
} // end of GetResult
diff --git a/storage/connect/tabmysql.h b/storage/connect/tabmysql.h
index 56d21550df6..5d8f32e9f21 100644
--- a/storage/connect/tabmysql.h
+++ b/storage/connect/tabmysql.h
@@ -30,6 +30,7 @@ class MYSQLDEF : public TABDEF {/* Logical table description */
inline PSZ GetHostname(void) {return Hostname;};
inline PSZ GetDatabase(void) {return Database;};
inline PSZ GetTabname(void) {return Tabname;}
+ inline PSZ GetSrcdef(void) {return Srcdef;}
inline PSZ GetUsername(void) {return Username;};
inline PSZ GetPassword(void) {return Password;};
inline int GetPortnumber(void) {return Portnumber;}
@@ -44,9 +45,11 @@ class MYSQLDEF : public TABDEF {/* Logical table description */
PSZ Hostname; /* Host machine to use */
PSZ Database; /* Database to be used by server */
PSZ Tabname; /* External table name */
+ PSZ Srcdef; /* The source table SQL definition */
PSZ Username; /* User logon name */
PSZ Password; /* Password logon info */
int Portnumber; /* MySQL port number (0 = default) */
+ bool Isview; /* TRUE if this table is a MySQL view */
bool Bind; /* Use prepared statement on insert */
bool Delayed; /* Delayed insert */
}; // end of MYSQLDEF
@@ -72,6 +75,7 @@ class TDBMYSQL : public TDBASE {
virtual int GetProgMax(PGLOBAL g);
virtual void ResetDB(void) {N = 0;}
virtual int RowNumber(PGLOBAL g, bool b = FALSE);
+ virtual bool IsView(void) {return Isview;}
void SetDatabase(LPCSTR db) {Database = (char*)db;}
// Database routines
@@ -83,6 +87,10 @@ class TDBMYSQL : public TDBASE {
virtual int DeleteDB(PGLOBAL g, int irc);
virtual void CloseDB(PGLOBAL g);
+ // Specific routines
+ bool SetColumnRanks(PGLOBAL g);
+ PCOL MakeFieldColumn(PGLOBAL g, char *name);
+
protected:
// Internal functions
bool MakeSelect(PGLOBAL g);
@@ -99,9 +107,11 @@ class TDBMYSQL : public TDBASE {
char *Pwd; // Password logon info
char *Database; // Database to be used by server
char *Tabname; // External table name
+ char *Srcdef; // The source table SQL definition
char *Query; // Points to SQL query
- char *Qbuf; // Used for not prepared insert
+ char *Qbuf; // Used for not prepared insert
bool Fetched; // True when fetch was done
+ bool Isview; // True if this table is a MySQL view
bool Prep; // Use prepared statement on insert
bool Delayed; // Use delayed insert
int m_Rc; // Return code from command
@@ -119,6 +129,7 @@ class MYSQLCOL : public COLBLK {
public:
// Constructors
MYSQLCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am = "MYSQL");
+ MYSQLCOL(MYSQL_FIELD *fld, PTDB tdbp, int i, PSZ am = "MYSQL");
MYSQLCOL(MYSQLCOL *colp, PTDB tdbp); // Constructor used in copy process
// Implementation
@@ -129,6 +140,7 @@ class MYSQLCOL : public COLBLK {
virtual bool SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check);
virtual void ReadColumn(PGLOBAL g);
virtual void WriteColumn(PGLOBAL g);
+ bool FindRank(PGLOBAL g);
protected:
// Default constructor not to be used
diff --git a/storage/connect/taboccur.cpp b/storage/connect/taboccur.cpp
index 2f721c6a7cf..6c33aefbb68 100644
--- a/storage/connect/taboccur.cpp
+++ b/storage/connect/taboccur.cpp
@@ -85,20 +85,44 @@ PTDB OCCURDEF::GetTable(PGLOBAL g, MODE m)
/***********************************************************************/
TDBOCCUR::TDBOCCUR(POCCURDEF tdp) : TDBPRX(tdp)
{
-//Tdbp = NULL; // Source table
+//Tdbp = NULL; // Source table (in TDBPRX)
Tabname = tdp->Tablep->GetName(); // Name of source table
- Colist = tdp->Colist; // List of source columns
- Xcolumn = tdp->Xcol; // Occur column name
- Rcolumn = tdp->Rcol; // Rank column name
- Xcolp = NULL; // To the OCCURCOL column
- Col = NULL; // To source column blocks array
- Mult = -1; // Multiplication factor
- N = 0; // The current table index
- M = 0; // The occurence rank
- RowFlag = 0; // 0: Ok, 1: Same, 2: Skip
+ Colist = tdp->Colist; // List of source columns
+ Xcolumn = tdp->Xcol; // Occur column name
+ Rcolumn = tdp->Rcol; // Rank column name
+ Xcolp = NULL; // To the OCCURCOL column
+ Col = NULL; // To source column blocks array
+ Mult = PrepareColist(); // Multiplication factor
+ N = 0; // The current table index
+ M = 0; // The occurence rank
+ RowFlag = 0; // 0: Ok, 1: Same, 2: Skip
} // end of TDBOCCUR constructor
/***********************************************************************/
+/* Prepare and count columns in the column list. */
+/***********************************************************************/
+int TDBOCCUR::PrepareColist(void)
+ {
+ char *p, *pn;
+ int n = 0;
+
+ // Count the number of columns and change separator into null char
+ for (pn = Colist; ; pn += (strlen(pn) + 1))
+ // Separator can be ; if colist was specified in the option_list
+ if ((p = strchr(pn, ',')) || (p = strchr(pn, ';'))) {
+ *p++ = '\0';
+ n++;
+ } else {
+ if (*pn)
+ n++;
+
+ break;
+ } // endif p
+
+ return n;
+ } // end of PrepareColist
+
+/***********************************************************************/
/* Allocate OCCUR/SRC column description block. */
/***********************************************************************/
PCOL TDBOCCUR::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
@@ -111,14 +135,8 @@ PCOL TDBOCCUR::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
} else if (!stricmp(cdp->GetName(), Xcolumn)) {
// Allocate the OCCUR column
colp = Xcolp = new(g) OCCURCOL(cdp, this, n);
- } else {
- colp = new(g) PRXCOL(cdp, this, cprec, n);
-
- if (((PPRXCOL)colp)->Init(g))
- return NULL;
-
- return colp;
- } //endif name
+ } else
+ return new(g) PRXCOL(cdp, this, cprec, n);
if (cprec) {
colp->SetNext(cprec->GetNext());
@@ -136,75 +154,100 @@ PCOL TDBOCCUR::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
/***********************************************************************/
bool TDBOCCUR::InitTable(PGLOBAL g)
{
- if (!Tdbp) {
+ if (!Tdbp)
// Get the table description block of this table
- if (!(Tdbp = (PTDBASE)GetSubTable(g, ((POCCURDEF)To_Def)->Tablep)))
+ if (!(Tdbp = GetSubTable(g, ((POCCURDEF)To_Def)->Tablep, TRUE)))
return TRUE;
- if (MakeColumnList(g) < 0)
+ if (!Tdbp->IsView())
+ if (MakeColumnList(g))
return TRUE;
- } // endif Tdbp
-
return FALSE;
} // end of InitTable
/***********************************************************************/
/* Allocate OCCUR column description block. */
/***********************************************************************/
-int TDBOCCUR::MakeColumnList(PGLOBAL g)
+bool TDBOCCUR::MakeColumnList(PGLOBAL g)
{
- if (Mult < 0) {
- char *p, *pn;
- int i;
- int n = 0;
-
- // Count the number of columns and change separator into null char
- for (pn = Colist; ; pn += (strlen(pn) + 1))
- if ((p = strchr(pn, ',')) || (p = strchr(pn, ';'))) {
- *p++ = '\0';
- n++;
- } else {
- if (*pn)
- n++;
-
- break;
- } // endif p
+ char *pn;
+ int i;
+ PCOL colp;
- Col = (PCOL*)PlugSubAlloc(g, NULL, n * sizeof(PCOL));
+ for (colp = Columns; colp; colp = colp->GetNext())
+ if (colp->GetAmType() == TYPE_AM_PRX)
+ if (((PPRXCOL)colp)->Init(g))
+ return true;
- for (i = 0, pn = Colist; i < n; i++, pn += (strlen(pn) + 1)) {
- if (!(Col[i] = Tdbp->ColDB(g, pn, 0))) {
- // Column not found in table
- sprintf(g->Message, MSG(COL_ISNOT_TABLE), pn, Tabname);
- return -1;
- } // endif Col
+ Col = (PCOL*)PlugSubAlloc(g, NULL, Mult * sizeof(PCOL));
- if (Col[i]->InitValue(g)) {
- strcpy(g->Message, "OCCUR InitValue failed");
- return -1;
- } // endif InitValue
+ for (i = 0, pn = Colist; i < Mult; i++, pn += (strlen(pn) + 1)) {
+ if (!(Col[i] = Tdbp->ColDB(g, pn, 0))) {
+ // Column not found in table
+ sprintf(g->Message, MSG(COL_ISNOT_TABLE), pn, Tabname);
+ return true;
+ } // endif Col
- } // endfor i
+ if (Col[i]->InitValue(g)) {
+ strcpy(g->Message, "OCCUR InitValue failed");
+ return true;
+ } // endif InitValue
- // OCCUR column name defaults to the name of the list first column
- if (!Xcolumn)
- Xcolumn = Colist;
+ } // endfor i
- Mult = n;
- } // endif Mult
-
- return Mult;
+ return false;
} // end of MakeColumnList
/***********************************************************************/
+/* Allocate OCCUR column description block for a view. */
+/***********************************************************************/
+bool TDBOCCUR::ViewColumnList(PGLOBAL g)
+ {
+ char *pn;
+ int i;
+ PCOL colp, cp;
+ PTDBMY tdbp;
+
+ if (!Tdbp->IsView())
+ return false;
+
+ if (Tdbp->GetAmType() != TYPE_AM_MYSQL) {
+ strcpy(g->Message, "View is not MySQL");
+ return true;
+ } else
+ tdbp = (PTDBMY)Tdbp;
+
+ for (cp = Columns; cp; cp = cp->GetNext())
+ if (cp->GetAmType() == TYPE_AM_PRX) {
+ if ((colp = tdbp->MakeFieldColumn(g, cp->GetName()))) {
+ ((PPRXCOL)cp)->Colp = colp;
+ ((PPRXCOL)cp)->To_Val = colp->GetValue();
+ } else
+ return true;
+
+ } // endif Type
+
+ Col = (PCOL*)PlugSubAlloc(g, NULL, Mult * sizeof(PCOL));
+
+ for (i = 0, pn = Colist; i < Mult; i++, pn += (strlen(pn) + 1))
+ if (!(Col[i] = tdbp->MakeFieldColumn(g, pn))) {
+ // Column not found in table
+ sprintf(g->Message, MSG(COL_ISNOT_TABLE), pn, Tabname);
+ return true;
+ } // endif Col
+
+ return false;
+ } // end of ViewColumnList
+
+/***********************************************************************/
/* OCCUR GetMaxSize: returns the maximum number of rows in the table. */
/***********************************************************************/
int TDBOCCUR::GetMaxSize(PGLOBAL g)
{
if (MaxSize < 0) {
- if (InitTable(g))
- return NULL;
+ if (!(Tdbp = GetSubTable(g, ((POCCURDEF)To_Def)->Tablep, TRUE)))
+ return 0;
MaxSize = Mult * Tdbp->GetMaxSize(g);
} // endif MaxSize
@@ -252,7 +295,7 @@ bool TDBOCCUR::OpenDB(PGLOBAL g)
/* Do it here if not done yet. */
/*********************************************************************/
if (InitTable(g))
- return NULL;
+ return TRUE;
if (Xcolp)
// Lock this column so it is evaluated by its table only
@@ -269,7 +312,10 @@ bool TDBOCCUR::OpenDB(PGLOBAL g)
/*********************************************************************/
/* Do open the source table. */
/*********************************************************************/
- return Tdbp->OpenDB(g);
+ if (Tdbp->OpenDB(g))
+ return TRUE;
+
+ return ViewColumnList(g);
} // end of OpenDB
/***********************************************************************/
diff --git a/storage/connect/taboccur.h b/storage/connect/taboccur.h
index 076202be477..b7d51e05b7d 100644
--- a/storage/connect/taboccur.h
+++ b/storage/connect/taboccur.h
@@ -52,21 +52,22 @@ class TDBOCCUR : public TDBPRX {
TDBOCCUR(POCCURDEF tdp);
// Implementation
- virtual AMT GetAmType(void) {return TYPE_AM_OCCUR;}
- void SetTdbp(PTDBASE tdbp) {Tdbp = tdbp;}
+ virtual AMT GetAmType(void) {return TYPE_AM_OCCUR;}
+ void SetTdbp(PTDBASE tdbp) {Tdbp = tdbp;}
// Methods
- virtual void ResetDB(void) {N = 0; Tdbp->ResetDB();}
- virtual int RowNumber(PGLOBAL g, bool b = FALSE);
- PTDB GetSourceTable(PGLOBAL g);
- int MakeColumnList(PGLOBAL g);
+ virtual void ResetDB(void) {N = 0; Tdbp->ResetDB();}
+ virtual int RowNumber(PGLOBAL g, bool b = FALSE);
+ int PrepareColist(void);
+ bool MakeColumnList(PGLOBAL g);
+ bool ViewColumnList(PGLOBAL g);
// Database routines
- virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
- virtual bool InitTable(PGLOBAL g);
- virtual int GetMaxSize(PGLOBAL g);
- virtual bool OpenDB(PGLOBAL g);
- virtual int ReadDB(PGLOBAL g);
+ virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
+ virtual bool InitTable(PGLOBAL g);
+ virtual int GetMaxSize(PGLOBAL g);
+ virtual bool OpenDB(PGLOBAL g);
+ virtual int ReadDB(PGLOBAL g);
protected:
// Members
diff --git a/storage/connect/tabpivot.cpp b/storage/connect/tabpivot.cpp
index 4ae1b3ceae6..1a73f353970 100644
--- a/storage/connect/tabpivot.cpp
+++ b/storage/connect/tabpivot.cpp
@@ -1,7 +1,7 @@
/************ TabPivot C++ Program Source Code File (.CPP) *************/
/* PROGRAM NAME: TABPIVOT */
/* ------------- */
-/* Version 1.4 */
+/* Version 1.5 */
/* */
/* COPYRIGHT: */
/* ---------- */
@@ -41,11 +41,9 @@
#include "global.h"
#include "plgdbsem.h"
#include "xtable.h"
-//#include "xindex.h"
#include "tabcol.h"
#include "colblk.h"
-//#include "tabmysql.h"
-#include "myconn.h"
+#include "tabmysql.h"
#include "csort.h"
#include "tabutil.h"
#include "tabpivot.h"
@@ -55,381 +53,6 @@
extern "C" int trace;
-#if 0
-/***********************************************************************/
-/* Prepare the source table Query. */
-/***********************************************************************/
-PQRYRES TDBPIVOT::GetSourceTable(PGLOBAL g)
- {
- if (Qryp)
- return Qryp; // Already done
-
- if (Tabname) {
- char *def, *colist;
- size_t len = 0;
- PCOL colp;
- PDBUSER dup = (PDBUSER)g->Activityp->Aptr;
-
- if (InitTable(g))
- return NULL;
-
- // Evaluate the length of the column list
- for (colp = Tdbp->Columns; colp; colp = colp->GetNext())
- len += (strlen(colp->GetName()) + 2);
-
- *(colist = (char*)PlugSubAlloc(g, NULL, len)) = 0;
-
- // Locate the suballocated string (size is not known yet)
- def = (char*)PlugSubAlloc(g, NULL, 0);
- strcpy(def, "SELECT ");
-
- if (!Fncol) {
- for (colp = Tdbp->Columns; colp; colp = colp->GetNext())
- if (!Picol || stricmp(Picol, colp->GetName()))
- Fncol = colp->GetName();
-
- if (!Fncol) {
- strcpy(g->Message, MSG(NO_DEF_FNCCOL));
- return NULL;
- } // endif Fncol
-
- } else if (!(ColDB(g, Fncol, 0))) {
- // Function column not found in table
- sprintf(g->Message, MSG(COL_ISNOT_TABLE), Fncol, Tabname);
- return NULL;
- } // endif Fcolp
-
- if (!Picol) {
- // Find default Picol as the last one not equal to Fncol
- for (colp = Tdbp->Columns; colp; colp = colp->GetNext())
- if (!Fncol || stricmp(Fncol, colp->GetName()))
- Picol = colp->GetName();
-
- if (!Picol) {
- strcpy(g->Message, MSG(NO_DEF_PIVOTCOL));
- return NULL;
- } // endif Picol
-
- } else if (!(ColDB(g, Picol, 0))) {
- // Pivot column not found in table
- sprintf(g->Message, MSG(COL_ISNOT_TABLE), Picol, Tabname);
- return NULL;
- } // endif Xcolp
-
- // Make the other column list
- for (colp = Columns; colp; colp = colp->GetNext())
- if (stricmp(Picol, colp->GetName()) &&
- stricmp(Fncol, colp->GetName()))
- strcat(strcat(colist, colp->GetName()), ", ");
-
- // Add the Pivot column at the end of the list
- strcat(strcat(def, strcat(colist, Picol)), ", ");
-
- // Continue making the definition
- if (!GBdone) {
- // Make it suitable for Pivot by doing the group by
- strcat(strcat(def, Function), "(");
- strcat(strcat(strcat(def, Fncol), ") "), Fncol);
- strcat(strcat(def, " FROM "), Tabname);
- strcat(strcat(def, " GROUP BY "), colist);
- } else // Gbdone
- strcat(strcat(strcat(def, Fncol), " FROM "), Tabname);
-
- // Now we know how much was suballocated
- Tabsrc = (char*)PlugSubAlloc(g, NULL, strlen(def));
- } else {
- strcpy(g->Message, MSG(SRC_TABLE_UNDEF));
- return NULL;
- } // endif Tabsrc
-
- int w;
-
- // Open a MySQL connection for this table
- if (Myc.Open(g, Host, Database, User, Pwd, Port))
- return NULL;
-
- // Send the source command to MySQL
- if (Myc.ExecSQL(g, Tabsrc, &w) == RC_FX) {
- Myc.Close();
- return NULL;
- } // endif Exec
-
- // We must have a storage query to get pivot column values
- Qryp = Myc.GetResult(g);
- Myc.Close();
- Tqrp = new(g) TDBQRS(Qryp);
- Tqrp->OpenDB(g);
-
- if (MakePivotColumns(g) < 0)
- return NULL;
-
- return Qryp;
- } // end of GetSourceTable
-
-/***********************************************************************/
-/* Allocate PIVOT columns description block. */
-/***********************************************************************/
-int TDBPIVOT::MakePivotColumns(PGLOBAL g)
- {
- if (Mult < 0) {
- int ndif, n = 0, nblin = Qryp->Nblin;
- PVAL valp;
- PCOL cp;
- PSRCCOL colp;
- PFNCCOL cfnp;
-
- // Allocate all the source columns
- Tqrp->ColDB(g, NULL, 0);
- Columns = NULL; // Discard dummy columns blocks
-
- for (cp = Tqrp->GetColumns(); cp; cp = cp->GetNext()) {
- if (cp->InitValue(g))
- return -1;
-
- if (!stricmp(cp->GetName(), Picol)) {
- Xcolp = (PQRSCOL)cp;
- Xresp = Xcolp->GetCrp();
- Rblkp = Xresp->Kdata;
- } else if (!stricmp(cp->GetName(), Fncol)) {
- Fcolp = (PQRSCOL)cp;
- } else
- if ((colp = new(g) SRCCOL(cp, this, ++n))->Init(g, this))
- return -1;
-
- } // endfor cp
-
- if (!Xcolp) {
- sprintf(g->Message, MSG(COL_ISNOT_TABLE),
- Picol, Tabname ? Tabname : "TabSrc");
- return -1;
- } else if (!Fcolp) {
- sprintf(g->Message, MSG(COL_ISNOT_TABLE),
- Fncol, Tabname ? Tabname : "TabSrc");
- return -1;
- } // endif Fcolp
-
- // Before calling sort, initialize all
- Index.Size = nblin * sizeof(int);
- Index.Sub = TRUE; // Should be small enough
-
- if (!PlgDBalloc(g, NULL, Index))
- return -1;
-
- Offset.Size = (nblin + 1) * sizeof(int);
- Offset.Sub = TRUE; // Should be small enough
-
- if (!PlgDBalloc(g, NULL, Offset))
- return -2;
-
- ndif = Qsort(g, nblin);
-
- if (ndif < 0) { // error
- return -3;
- } else
- Ncol = ndif;
-
- // Now make the functional columns
- for (int i = 0; i < Ncol; i++) {
- // Allocate the Value used to retieve column names
- if (!(valp = AllocateValue(g, Xcolp->GetResultType(),
- Xcolp->GetLengthEx(), Xcolp->GetPrecision(),
- Xcolp->GetDomain(), Xcolp->GetTo_Tdb()->GetCat())))
- return -4;
-
- // Get the value that will be the generated column name
- valp->SetValue_pvblk(Rblkp, Pex[Pof[i]]);
-
- // Copy the functional column with new Name and new Value
- cfnp = (PFNCCOL)new(g) FNCCOL(Fcolp, this);
-
- // Initialize the generated column
- if (cfnp->InitColumn(g, valp))
- return -5;
-
- } // endfor i
-
- // Fields must be updated for ha_connect
-// if (UpdateTableFields(g, n + Ncol))
-// return -6;
-
- // This should be refined later
- Mult = nblin;
- } // endif Mult
-
- return Mult;
- } // end of MakePivotColumns
-
-/***********************************************************************/
-/* Update fields in the MySQL table structure */
-/* Note: this does not work. Indeed the new rows are correctly made */
-/* but the final result still specify the unmodified table and the */
-/* returned table only contains the original column values. */
-/* In addition, a new query on the table, when it is into the cache, */
-/* specifies all the new columns and fails because they do not belong */
-/* to the original table. */
-/***********************************************************************/
-bool TDBPIVOT::UpdateTableFields(PGLOBAL g, int n)
- {
- uchar *trec, *srec, *tptr, *sptr;
- int i = 0, k = 0;
- uint len;
- uint32 nmp, lwm;
- size_t buffsize;
- PCOL colp;
- PHC hc = ((MYCAT*)((PIVOTDEF*)To_Def)->Cat)->GetHandler();
- TABLE *table = hc->GetTable();
- st_mem_root *tmr = &table->mem_root;
- st_mem_root *smr = &table->s->mem_root;
- Field* *field;
- Field *fp, *tfncp, *sfncp;
- Field* *ntf;
- Field* *nsf;
-//my_bitmap_map *org_bitmap;
- const MY_BITMAP *map;
-
- // When sorting read_set selects all columns, so we use def_read_set
- map= (const MY_BITMAP *)&table->def_read_set;
-
- // Find the function field
- for (field= table->field; *field; field++) {
- fp= *field;
-
- if (bitmap_is_set(map, fp->field_index))
- if (!stricmp(fp->field_name, Fncol)) {
- tfncp = fp;
- break;
- } // endif Name
-
- } // endfor field
-
- for (field= table->s->field; *field; field++) {
- fp= *field;
-
- if (bitmap_is_set(map, fp->field_index))
- if (!stricmp(fp->field_name, Fncol)) {
- sfncp = fp;
- break;
- } // endif Name
-
- } // endfor field
-
- // Calculate the new buffer size
- len = tfncp->max_data_length();
- buffsize = table->s->rec_buff_length + len * Ncol;
-
- // Allocate the new record space
- if (!(tptr = trec = (uchar*)alloc_root(tmr, 2 * buffsize)))
- return TRUE;
-
- if (!(sptr = srec = (uchar*)alloc_root(smr, 2 * buffsize)))
- return TRUE;
-
-
- // Allocate the array of all new table field pointers
- if (!(ntf = (Field**)alloc_root(tmr, (uint)((n+1) * sizeof(Field*)))))
- return TRUE;
-
- // Allocate the array of all new table share field pointers
- if (!(nsf = (Field**)alloc_root(smr, (uint)((n+1) * sizeof(Field*)))))
- return TRUE;
-
- // First fields are the the ones of the source columns
- for (colp = Columns; colp; colp = colp->GetNext())
- if (colp->GetAmType() == TYPE_AM_SRC) {
- for (field= table->field; *field; field++) {
- fp= *field;
-
- if (bitmap_is_set(map, fp->field_index))
- if (!stricmp(colp->GetName(), fp->field_name)) {
- ntf[i] = fp;
- fp->field_index = i++;
- fp->ptr = tptr;
- tptr += fp->max_data_length();
- break;
- } // endif Name
-
- } // endfor field
-
- for (field= table->s->field; *field; field++) {
- fp= *field;
-
- if (bitmap_is_set(map, fp->field_index))
- if (!stricmp(colp->GetName(), fp->field_name)) {
- nsf[k] = fp;
- fp->field_index = k++;
- fp->ptr = srec;
- srec += fp->max_data_length();
- break;
- } // endif Name
-
- } // endfor field
-
- } // endif AmType
-
- // Now add the pivot generated columns
- for (colp = Columns; colp; colp = colp->GetNext())
- if (colp->GetAmType() == TYPE_AM_FNC) {
- if ((fp = (Field*)memdup_root(tmr, (char*)tfncp, tfncp->size_of()))) {
- ntf[i] = fp;
- fp->ptr = tptr;
- fp->field_name = colp->GetName();
- fp->field_index = i++;
- fp->vcol_info = NULL;
- fp->stored_in_db = TRUE;
- tptr += len;
- } else
- return TRUE;
-
- if ((fp = (Field*)memdup_root(smr, (char*)sfncp, sfncp->size_of()))) {
- nsf[i] = fp;
- fp->ptr = sptr;
- fp->field_name = colp->GetName();
- fp->field_index = k++;
- fp->vcol_info = NULL;
- fp->stored_in_db = TRUE;
- sptr += len;
- } else
- return TRUE;
-
- } // endif AM_FNC
-
- // Mark end of the list
- ntf[i] = NULL;
- nsf[k] = NULL;
-
- // Update the table fields
- nmp = (uint32)((1<<i) - 1);
- lwm = (uint32)((-1)<<i);
- table->field = ntf;
- table->used_fields = i;
- table->record[0] = trec;
- table->record[1] = trec + buffsize;
- *table->def_read_set.bitmap = nmp;
- *table->def_read_set.last_word_ptr = nmp;
- table->def_read_set.last_word_mask = lwm;
- table->def_read_set.n_bits = i;
- *table->read_set->bitmap = nmp;
- *table->read_set->last_word_ptr = nmp;
- table->read_set->last_word_mask = lwm;
- table->read_set->n_bits = i;
- table->write_set->n_bits = i;
- *table->vcol_set->bitmap = 0;
- table->vcol_set->n_bits = i;
-
- // and the share fields
- table->s->field = nsf;
- table->s->reclength = sptr - srec;
- table->s->stored_rec_length = sptr - srec;
- table->s->fields = k;
- table->s->stored_fields = k;
- table->s->rec_buff_length = buffsize;
-//table->s->varchar_fields = ???;
-//table->s->db_record_offset = ???;
-//table->s->null_field_first = ???;
- return FALSE;
- } // end of UpdateTableFields
-#endif // 0
-
/* --------------- Implementation of the PIVOT classes --------------- */
/***********************************************************************/
@@ -451,13 +74,12 @@ bool PIVOTDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
char *p1, *p2;
PHC hc = ((MYCAT*)Cat)->GetHandler();
- if (!PRXDEF::DefineAM(g, am, poff)) {
- Tabname = (char*)Tablep->GetName();
- DB = (char*)Tablep->GetQualifier();
- } else {
- DB = Cat->GetStringCatInfo(g, "Database", "*");
- Tabsrc = Cat->GetStringCatInfo(g, "SrcDef", NULL);
- } // endif
+ if (PRXDEF::DefineAM(g, am, poff))
+ return TRUE;
+
+ Tabname = (char*)Tablep->GetName();
+ DB = (char*)Tablep->GetQualifier();
+ Tabsrc = (char*)Tablep->GetSrc();
Host = Cat->GetStringCatInfo(g, "Host", "localhost");
User = Cat->GetStringCatInfo(g, "User", "*");
@@ -477,7 +99,7 @@ bool PIVOTDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
GBdone = Cat->GetBoolCatInfo("Groupby", false);
Accept = Cat->GetBoolCatInfo("Accept", false);
Port = Cat->GetIntCatInfo("Port", 3306);
- Desc = (Tabname) ? Tabname : Tabsrc;
+ Desc = (Tabsrc) ? Tabsrc : Tabname;
return FALSE;
} // end of DefineAM
@@ -521,6 +143,25 @@ TDBPIVOT::TDBPIVOT(PPIVOTDEF tdp) : TDBPRX(tdp)
} // end of TDBPIVOT constructor
/***********************************************************************/
+/* Allocate source column description block. */
+/***********************************************************************/
+PCOL TDBPIVOT::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+ {
+ PCOL colp;
+
+ if (cdp->GetOffset()) {
+ colp = new(g) FNCCOL(cdp, this, cprec, n);
+
+ if (cdp->GetOffset() > 1)
+ Dcolp = colp;
+
+ } else
+ colp = new(g) SRCCOL(cdp, this, cprec, n);
+
+ return colp;
+ } // end of MakeCol
+
+/***********************************************************************/
/* Prepare the source table Query. */
/***********************************************************************/
bool TDBPIVOT::GetSourceTable(PGLOBAL g)
@@ -528,72 +169,74 @@ bool TDBPIVOT::GetSourceTable(PGLOBAL g)
if (Tdbp)
return false; // Already done
- if (Tabname) {
- PTABDEF defp;
- PCOLDEF cdp;
-
- if (InitTable(g))
+ if (!Tabsrc && Tabname) {
+ // Get the table description block of this table
+ if (!(Tdbp = GetSubTable(g, ((PPIVOTDEF)To_Def)->Tablep, true)))
return true;
- else
- defp = Tdbp->GetDef();
- if (!Fncol) {
- for (cdp = defp->GetCols(); cdp; cdp = cdp->GetNext())
- if (!Picol || stricmp(Picol, cdp->GetName()))
- Fncol = cdp->GetName();
+ if (!Tdbp->IsView()) {
+ PCOLDEF cdp;
+ PTABDEF defp = Tdbp->GetDef();
if (!Fncol) {
- strcpy(g->Message, MSG(NO_DEF_FNCCOL));
- return true;
+ for (cdp = defp->GetCols(); cdp; cdp = cdp->GetNext())
+ if (!Picol || stricmp(Picol, cdp->GetName()))
+ Fncol = cdp->GetName();
+
+ if (!Fncol) {
+ strcpy(g->Message, MSG(NO_DEF_FNCCOL));
+ return true;
+ } // endif Fncol
+
} // endif Fncol
-
- } // endif Fncol
-
- if (!Picol) {
- // Find default Picol as the last one not equal to Fncol
- for (cdp = defp->GetCols(); cdp; cdp = cdp->GetNext())
- if (!Fncol || stricmp(Fncol, cdp->GetName()))
- Picol = cdp->GetName();
-
+
if (!Picol) {
- strcpy(g->Message, MSG(NO_DEF_PIVOTCOL));
- return true;
+ // Find default Picol as the last one not equal to Fncol
+ for (cdp = defp->GetCols(); cdp; cdp = cdp->GetNext())
+ if (!Fncol || stricmp(Fncol, cdp->GetName()))
+ Picol = cdp->GetName();
+
+ if (!Picol) {
+ strcpy(g->Message, MSG(NO_DEF_PIVOTCOL));
+ return true;
+ } // endif Picol
+
} // endif Picol
-
- } // endif Picol
-
- if (!GBdone) {
- char *colist;
- // Locate the suballocated colist (size is not known yet)
- *(colist = (char*)PlugSubAlloc(g, NULL, 0)) = 0;
+ if (!GBdone) {
+ char *colist;
- // Make the column list
- for (cdp = To_Def->GetCols(); cdp; cdp = cdp->GetNext())
- if (!cdp->GetOffset())
- strcat(strcat(colist, cdp->GetName()), ", ");
+ // Locate the suballocated colist (size is not known yet)
+ *(colist = (char*)PlugSubAlloc(g, NULL, 0)) = 0;
- // Add the Pivot column at the end of the list
- strcat(colist, Picol);
+ // Make the column list
+ for (cdp = To_Def->GetCols(); cdp; cdp = cdp->GetNext())
+ if (!cdp->GetOffset())
+ strcat(strcat(colist, cdp->GetName()), ", ");
- // Now we know how much was suballocated
- PlugSubAlloc(g, NULL, strlen(colist));
+ // Add the Pivot column at the end of the list
+ strcat(colist, Picol);
- // Locate the source string (size is not known yet)
- Tabsrc = (char*)PlugSubAlloc(g, NULL, 0);
-
- // Start making the definition
- strcat(strcat(strcpy(Tabsrc, "SELECT "), colist), ", ");
+ // Now we know how much was suballocated
+ PlugSubAlloc(g, NULL, strlen(colist));
+
+ // Locate the source string (size is not known yet)
+ Tabsrc = (char*)PlugSubAlloc(g, NULL, 0);
+
+ // Start making the definition
+ strcat(strcat(strcpy(Tabsrc, "SELECT "), colist), ", ");
- // Make it suitable for Pivot by doing the group by
- strcat(strcat(Tabsrc, Function), "(");
- strcat(strcat(strcat(Tabsrc, Fncol), ") "), Fncol);
- strcat(strcat(Tabsrc, " FROM "), Tabname);
- strcat(strcat(Tabsrc, " GROUP BY "), colist);
+ // Make it suitable for Pivot by doing the group by
+ strcat(strcat(Tabsrc, Function), "(");
+ strcat(strcat(strcat(Tabsrc, Fncol), ") "), Fncol);
+ strcat(strcat(Tabsrc, " FROM "), Tabname);
+ strcat(strcat(Tabsrc, " GROUP BY "), colist);
- // Now we know how much was suballocated
- PlugSubAlloc(g, NULL, strlen(Tabsrc));
- } // endif !GBdone
+ // Now we know how much was suballocated
+ PlugSubAlloc(g, NULL, strlen(Tabsrc));
+ } // endif !GBdone
+
+ } // endif IsView
} else if (!Tabsrc) {
strcpy(g->Message, MSG(SRC_TABLE_UNDEF));
@@ -601,26 +244,76 @@ bool TDBPIVOT::GetSourceTable(PGLOBAL g)
} // endif
if (Tabsrc) {
- MYSQLC myc; // MySQL connection class
- PQRYRES qryp;
- PCOLRES crp;
- int w;
+ // Get the new table description block of this source table
+ PTABLE tablep = new(g) XTAB("whatever", Tabsrc);
+
+ tablep->SetQualifier(Database);
- // Open a MySQL connection for this table
- if (myc.Open(g, Host, Database, User, Pwd, Port))
+ if (!(Tdbp = GetSubTable(g, tablep, true)))
return true;
- // Send the source command to MySQL
- if (myc.ExecSQL(g, Tabsrc, &w) == RC_FX) {
- myc.Close();
+ } // endif Tabsrc
+
+ return false;
+ } // end of GetSourceTable
+
+/***********************************************************************/
+/* Make the required pivot columns. */
+/***********************************************************************/
+bool TDBPIVOT::MakePivotColumns(PGLOBAL g)
+ {
+ if (!Tdbp->IsView()) {
+ // Now it is time to allocate the pivot and function columns
+ if (!(Fcolp = Tdbp->ColDB(g, Fncol, 0))) {
+ // Function column not found in table
+ sprintf(g->Message, MSG(COL_ISNOT_TABLE), Fncol, Tabname);
+ return true;
+ } else if (Fcolp->InitValue(g))
return true;
- } // endif Exec
- // We must have a storage query to get pivot column values
- qryp = myc.GetResult(g);
- myc.Close();
- Tdbp = new(g) TDBQRS(qryp);
+ if (!(Xcolp = Tdbp->ColDB(g, Picol, 0))) {
+ // Pivot column not found in table
+ sprintf(g->Message, MSG(COL_ISNOT_TABLE), Picol, Tabname);
+ return true;
+ } else if (Xcolp->InitValue(g))
+ return true;
+
+ // Check and initialize the subtable columns
+ for (PCOL cp = Columns; cp; cp = cp->GetNext())
+ if (cp->GetAmType() == TYPE_AM_SRC) {
+ if (((PSRCCOL)cp)->Init(g))
+ return TRUE;
+
+ } else if (cp->GetAmType() == TYPE_AM_FNC)
+ if (((PFNCCOL)cp)->InitColumn(g))
+ return TRUE;
+
+ } // endif isview
+
+ return false;
+ } // end of MakePivotColumns
+/***********************************************************************/
+/* Make the required pivot columns for an object view. */
+/***********************************************************************/
+bool TDBPIVOT::MakeViewColumns(PGLOBAL g)
+ {
+ if (Tdbp->IsView()) {
+ // Tdbp is a view ColDB cannot be used
+ PCOL colp, cp;
+ PTDBMY tdbp;
+
+ if (Tdbp->GetAmType() != TYPE_AM_MYSQL) {
+ strcpy(g->Message, "View is not MySQL");
+ return true;
+ } else
+ tdbp = (PTDBMY)Tdbp;
+
+ if (!Fncol || !Picol) {
+ strcpy(g->Message, "Missing Function or Pivot column");
+ return true;
+ } // endif
+#if 0
if (!Fncol) {
for (crp = qryp->Colresp; crp; crp = crp->Next)
if (!Picol || stricmp(Picol, crp->Name))
@@ -645,45 +338,33 @@ bool TDBPIVOT::GetSourceTable(PGLOBAL g)
} // endif Picol
} // endif Picol
+#endif // 0
- } // endif Tabsrc
-
- // Now it is time to allocate the pivot and function columns
- if (!(Fcolp = Tdbp->ColDB(g, Fncol, 0))) {
- // Function column not found in table
- sprintf(g->Message, MSG(COL_ISNOT_TABLE), Fncol, Tabname);
- return true;
- } else if (Fcolp->InitValue(g))
- return true;
-
- if (!(Xcolp = Tdbp->ColDB(g, Picol, 0))) {
- // Pivot column not found in table
- sprintf(g->Message, MSG(COL_ISNOT_TABLE), Picol, Tabname);
- return true;
- } else if (Xcolp->InitValue(g))
- return true;
-
- return false;
- } // end of GetSourceTable
+ // Now it is time to allocate the pivot and function columns
+ if (!(Fcolp = tdbp->MakeFieldColumn(g, Fncol)))
+ return true;
-/***********************************************************************/
-/* Allocate source column description block. */
-/***********************************************************************/
-PCOL TDBPIVOT::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
- {
- PCOL colp;
+ if (!(Xcolp = tdbp->MakeFieldColumn(g, Picol)))
+ return true;
- if (cdp->GetOffset()) {
- colp = new(g) FNCCOL(cdp, this, cprec, n);
+ // Check and initialize the subtable columns
+ for (cp = Columns; cp; cp = cp->GetNext())
+ if (cp->GetAmType() == TYPE_AM_SRC) {
+ if ((colp = tdbp->MakeFieldColumn(g, cp->GetName()))) {
+ ((PSRCCOL)cp)->Colp = colp;
+ ((PSRCCOL)cp)->To_Val = colp->GetValue();
+ cp->AddStatus(BUF_READ); // All is done here
+ } else
+ return true;
- if (cdp->GetOffset() > 1)
- Dcolp = colp;
+ } else if (cp->GetAmType() == TYPE_AM_FNC)
+ if (((PFNCCOL)cp)->InitColumn(g))
+ return TRUE;
- } else
- colp = new(g) SRCCOL(cdp, this, cprec, n);
+ } // endif isview
- return colp;
- } // end of MakeCol
+ return false;
+ } // end of MakeViewColumns
/***********************************************************************/
/* PIVOT GetMaxSize: returns the maximum number of rows in the table. */
@@ -696,7 +377,7 @@ int TDBPIVOT::GetMaxSize(PGLOBAL g)
return MaxSize;
#endif // 0
- return 0;
+ return 10;
} // end of GetMaxSize
/***********************************************************************/
@@ -713,8 +394,6 @@ int TDBPIVOT::RowNumber(PGLOBAL g, bool b)
/***********************************************************************/
bool TDBPIVOT::OpenDB(PGLOBAL g)
{
-//PDBUSER dup = (PDBUSER)g->Activityp->Aptr;
-
if (Use == USE_OPEN) {
/*******************************************************************/
/* Table already open, just replace it at its beginning. */
@@ -746,18 +425,10 @@ bool TDBPIVOT::OpenDB(PGLOBAL g)
/*********************************************************************/
if (GetSourceTable(g))
return TRUE;
-
- /*********************************************************************/
- /* Check and initialize the subtable columns. */
- /*********************************************************************/
- for (PCOL cp = Columns; cp; cp = cp->GetNext())
- if (cp->GetAmType() == TYPE_AM_SRC) {
- if (((PPRXCOL)cp)->Init(g))
- return TRUE;
-
- } else if (cp->GetAmType() == TYPE_AM_FNC)
- if (((PFNCCOL)cp)->InitColumn(g))
- return TRUE;
+
+ // For tables, columns must be allocated before opening
+ if (MakePivotColumns(g))
+ return TRUE;
/*********************************************************************/
/* Physically open the object table. */
@@ -765,7 +436,10 @@ bool TDBPIVOT::OpenDB(PGLOBAL g)
if (Tdbp->OpenDB(g))
return TRUE;
- return FALSE;
+ /*********************************************************************/
+ /* Make all required pivot columns for object views. */
+ /*********************************************************************/
+ return MakeViewColumns(g);
} // end of OpenDB
/***********************************************************************/
@@ -881,17 +555,6 @@ void TDBPIVOT::CloseDB(PGLOBAL g)
} // end of CloseDB
-#if 0
-/***********************************************************************/
-/* TDBPIVOT: Compare routine for sorting pivot column values. */
-/***********************************************************************/
-int TDBPIVOT::Qcompare(int *i1, int *i2)
- {
- // TODO: the actual comparison between pivot column result values.
- return Rblkp->CompVal(*i1, *i2);
- } // end of Qcompare
-#endif // 0
-
// ------------------------ FNCCOL functions ----------------------------
/***********************************************************************/
@@ -948,8 +611,6 @@ bool FNCCOL::CompareColumn(void)
SRCCOL::SRCCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int n)
: PRXCOL(cdp, tdbp, cprec, n)
{
- // Set additional SRC access method information for column.
-//Cnval = NULL;
} // end of SRCCOL constructor
/***********************************************************************/
@@ -960,9 +621,6 @@ bool SRCCOL::Init(PGLOBAL g)
if (PRXCOL::Init(g))
return true;
- // Will contain the last value
-//Cnval = AllocateValue(g, Value, TYPE_VOID);
-
AddStatus(BUF_READ); // All is done here
return false;
} // end of SRCCOL constructor
@@ -972,7 +630,6 @@ bool SRCCOL::Init(PGLOBAL g)
/***********************************************************************/
void SRCCOL::SetColumn(void)
{
-//Cnval->SetValue_pval(Value);
Value->SetValue_pval(To_Val);
} // end of SetColumn
@@ -982,315 +639,7 @@ void SRCCOL::SetColumn(void)
bool SRCCOL::CompareLast(void)
{
// Compare the unconverted values
-//return !Cnval->IsEqual(Colp->GetValue(), true);
return !Value->IsEqual(To_Val, true);
} // end of CompareColumn
-
-/* ------------------------------------------------------------------- */
-
-/***********************************************************************/
-/* Implementation of the TDBQRS class. */
-/***********************************************************************/
-TDBQRS::TDBQRS(PTDBQRS tdbp) : TDBASE(tdbp)
- {
- Qrp = tdbp->Qrp;
- CurPos = tdbp->CurPos;
- } // end of TDBQRS copy constructor
-
-// Method
-PTDB TDBQRS::CopyOne(PTABS t)
- {
- PTDB tp;
- PQRSCOL cp1, cp2;
- PGLOBAL g = t->G; // Is this really useful ???
-
- tp = new(g) TDBQRS(this);
-
- for (cp1 = (PQRSCOL)Columns; cp1; cp1 = (PQRSCOL)cp1->GetNext()) {
- cp2 = new(g) QRSCOL(cp1, tp); // Make a copy
- NewPointer(t, cp1, cp2);
- } // endfor cp1
-
- return tp;
- } // end of CopyOne
-
-#if 0 // The TDBASE functions return NULL when To_Def is NULL
-/***********************************************************************/
-/* Return the pointer on the DB catalog this table belongs to. */
-/***********************************************************************/
-PCATLG TDBQRS::GetCat(void)
- {
- // To_Def is null for QRYRES tables
- return NULL;
- } // end of GetCat
-
-/***********************************************************************/
-/* Return the datapath of the DB this table belongs to. */
-/***********************************************************************/
-PSZ TDBQRS::GetPath(void)
- {
- // To_Def is null for QRYRES tables
- return NULL;
- } // end of GetPath
-#endif // 0
-
-/***********************************************************************/
-/* Initialize QRS column description block construction. */
-/* name is used to call columns by name. */
-/* num is used by LNA to construct columns by index number. */
-/* Note: name=Null and num=0 for constructing all columns (select *) */
-/***********************************************************************/
-PCOL TDBQRS::ColDB(PGLOBAL g, PSZ name, int num)
- {
- int i;
- PCOLRES crp;
- PCOL cp, colp = NULL, cprec = NULL;
-
- if (trace)
- htrc("QRS ColDB: colname=%s tabname=%s num=%d\n",
- SVP(name), Name, num);
-
- for (crp = Qrp->Colresp, i = 1; crp; crp = crp->Next, i++)
- if ((!name && !num) ||
- (name && !stricmp(crp->Name, name)) || num == i) {
- // Check for existence of desired column
- // Also find where to insert the new block
- for (cp = Columns; cp; cp = cp->GetNext())
- if (cp->GetIndex() < i)
- cprec = cp;
- else if (cp->GetIndex() == i)
- break;
-
- if (trace) {
- if (cp)
- htrc("cp(%d).Name=%s cp=%p\n", i, cp->GetName(), cp);
- else
- htrc("cp(%d) cp=%p\n", i, cp);
- } // endif trace
-
- // Now take care of Column Description Block
- if (cp)
- colp = cp;
- else
- colp = new(g) QRSCOL(g, crp, this, cprec, i);
-
- if (name || num)
- break;
- else
- cprec = colp;
-
- } // endif Name
-
- return (colp);
- } // end of ColDB
-
-/***********************************************************************/
-/* QRS GetMaxSize: returns maximum table size in number of lines. */
-/***********************************************************************/
-int TDBQRS::GetMaxSize(PGLOBAL g)
- {
- MaxSize = Qrp->Maxsize;
- return MaxSize;
- } // end of GetMaxSize
-
-/***********************************************************************/
-/* RowNumber: returns the current row ordinal number. */
-/***********************************************************************/
-int TDBQRS::RowNumber(PGLOBAL g, BOOL b)
- {
- return (CurPos + 1);
- } // end of RowNumber
-
-/***********************************************************************/
-/* QRS Access Method opening routine. */
-/* New method now that this routine is called recursively (last table */
-/* first in reverse order): index blocks are immediately linked to */
-/* join block of next table if it exists or else are discarted. */
-/***********************************************************************/
-bool TDBQRS::OpenDB(PGLOBAL g)
- {
- if (trace)
- htrc("QRS OpenDB: tdbp=%p tdb=R%d use=%d key=%p mode=%d\n",
- this, Tdb_No, Use, To_Key_Col, Mode);
-
- if (Mode != MODE_READ) {
- sprintf(g->Message, MSG(BAD_QUERY_OPEN), Mode);
- return TRUE;
- } // endif Mode
-
- CurPos = -1;
-
- if (Use == USE_OPEN)
- return FALSE;
-
- /*********************************************************************/
- /* Open (retrieve data from) the query if not already open. */
- /*********************************************************************/
- Use = USE_OPEN; // Do it now in case we are recursively called
-
- return FALSE;
- } // end of OpenDB
-
-/***********************************************************************/
-/* GetRecpos: returns current position of next sequential read. */
-/***********************************************************************/
-int TDBQRS::GetRecpos(void)
- {
- return (CurPos);
- } // end of GetRecpos
-
-/***********************************************************************/
-/* ReadDB: Data Base read routine for QRS access method. */
-/***********************************************************************/
-int TDBQRS::ReadDB(PGLOBAL g)
- {
- int rc = RC_OK;
-
- if (trace)
- htrc("QRS ReadDB: R%d CurPos=%d key=%p link=%p Kindex=%p\n",
- GetTdb_No(), CurPos, To_Key_Col, To_Link, To_Kindex);
-
-#if 0
- if (To_Kindex) {
- /*******************************************************************/
- /* Reading is by an index table. */
- /*******************************************************************/
- int recpos = To_Kindex->Fetch(g);
-
- switch (recpos) {
- case -1: // End of file reached
- rc = RC_EF;
- break;
- case -2: // No match for join
- rc = RC_NF;
- break;
- case -3: // Same record as last non null one
- rc = RC_OK;
- break;
- default:
- /***************************************************************/
- /* Set the file position according to record to read. */
- /***************************************************************/
- CurPos = recpos;
- } // endswitch recpos
-
- if (trace)
- htrc("Position is now %d\n", CurPos);
-
- } else
-#endif // 0
- /*******************************************************************/
- /* !To_Kindex ---> sequential reading */
- /*******************************************************************/
- rc = (++CurPos < Qrp->Nblin) ? RC_OK : RC_EF;
-
- return rc;
- } // end of ReadDB
-
-/***********************************************************************/
-/* Dummy WriteDB: just send back an error return. */
-/***********************************************************************/
-int TDBQRS::WriteDB(PGLOBAL g)
- {
- strcpy(g->Message, MSG(QRY_READ_ONLY));
- return RC_FX;
- } // end of WriteDB
-
-/***********************************************************************/
-/* Dummy DeleteDB routine, just returns an error code. */
-/***********************************************************************/
-int TDBQRS::DeleteDB(PGLOBAL g, int irc)
- {
- strcpy(g->Message, MSG(NO_QRY_DELETE));
- return RC_FX;
- } // end of DeleteDB
-
-/***********************************************************************/
-/* Data Base close routine for QRS access method. */
-/***********************************************************************/
-void TDBQRS::CloseDB(PGLOBAL g)
- {
-//if (To_Kindex) {
-// To_Kindex->Close();
-// To_Kindex = NULL;
-// } // endif
-
- if (trace)
- htrc("Qryres CloseDB");
-
-//Qryp->Sqlp->CloseDB();
- } // end of CloseDB
-
-// ------------------------ QRSCOL functions ----------------------------
-
-/***********************************************************************/
-/* QRSCOL public constructor. */
-/***********************************************************************/
-QRSCOL::QRSCOL(PGLOBAL g, PCOLRES crp, PTDB tdbp, PCOL cprec, int i)
- : COLBLK(NULL, tdbp, i)
- {
- if (cprec) {
- Next = cprec->GetNext();
- cprec->SetNext(this);
- } else {
- Next = tdbp->GetColumns();
- tdbp->SetColumns(this);
- } // endif cprec
-
- // Set additional QRS access method information for column.
- Crp = crp;
- Name = Crp->Name;
- Long = Crp->Clen;
- Buf_Type = crp->Type;
- strcpy(Format.Type, GetFormatType(Buf_Type));
- Format.Length = (short)Long;
- Format.Prec = (short)Crp->Prec;
-
- if (trace) {
- htrc("Making new QRSCOL C%d %s at %p\n", Index, Name, this);
- htrc(" BufType=%d Long=%d length=%d clen=%d\n",
- Buf_Type, Long, Format.Length, Crp->Clen);
- } // endif trace
-
- } // end of QRSCOL constructor
-
-/***********************************************************************/
-/* QRSCOL constructor used for copying columns. */
-/* tdbp is the pointer to the new table descriptor. */
-/***********************************************************************/
-QRSCOL::QRSCOL(QRSCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
- {
- Crp = col1->Crp;
- } // end of QRSCOL copy constructor
-
-/***********************************************************************/
-/* ReadColumn: what this routine does is to extract the RESCOL block */
-/* current value and convert it to the column buffer type. */
-/***********************************************************************/
-void QRSCOL::ReadColumn(PGLOBAL g)
- {
- PTDBQRS tdbp = (PTDBQRS)To_Tdb;
-
- if (trace)
- htrc("QRS RC: col %s R%d type=%d CurPos=%d Len=%d\n",
- Name, tdbp->GetTdb_No(), Buf_Type, tdbp->CurPos, Crp->Clen);
-
- if (Crp->Kdata)
- Value->SetValue_pvblk(Crp->Kdata, tdbp->CurPos);
- else
- Value->Reset();
-
- } // end of ReadColumn
-
-/***********************************************************************/
-/* Make file output of a Dos column descriptor block. */
-/***********************************************************************/
-void QRSCOL::Print(PGLOBAL g, FILE *f, uint n)
- {
- COLBLK::Print(g, f, n);
-
- fprintf(f, " Crp=%p\n", Crp);
- } // end of Print
-
/* --------------------- End of TabPivot/TabQrs ---------------------- */
diff --git a/storage/connect/tabpivot.h b/storage/connect/tabpivot.h
index bed288dc560..e869d1cae6c 100644
--- a/storage/connect/tabpivot.h
+++ b/storage/connect/tabpivot.h
@@ -1,15 +1,14 @@
/************** TabPivot H Declares Source Code File (.H) **************/
-/* Name: TABPIVOT.H Version 1.3 */
+/* Name: TABPIVOT.H Version 1.4 */
/* */
-/* (C) Copyright to the author Olivier BERTRAND 2005-2012 */
+/* (C) Copyright to the author Olivier BERTRAND 2005-2013 */
/* */
/* This file contains the PIVOT classes declares. */
/***********************************************************************/
+typedef class PIVOTDEF *PPIVOTDEF;
typedef class TDBPIVOT *PTDBPIVOT;
typedef class FNCCOL *PFNCCOL;
typedef class SRCCOL *PSRCCOL;
-typedef class TDBQRS *PTDBQRS;
-typedef class QRSCOL *PQRSCOL;
/* -------------------------- PIVOT classes -------------------------- */
@@ -22,7 +21,6 @@ typedef class QRSCOL *PQRSCOL;
/***********************************************************************/
/* PIVOT table. */
/***********************************************************************/
-//ass DllExport PIVOTDEF : public PRXDEF {/* Logical table description */
class PIVOTDEF : public PRXDEF { /* Logical table description */
friend class TDBPIVOT;
public:
@@ -55,22 +53,16 @@ class PIVOTDEF : public PRXDEF { /* Logical table description */
/***********************************************************************/
/* This is the class declaration for the PIVOT table. */
/***********************************************************************/
-//ass DllExport TDBPIVOT : public TDBASE, public CSORT {
class TDBPIVOT : public TDBPRX {
friend class FNCCOL;
-//friend class SRCCOL;
public:
// Constructor
TDBPIVOT(PPIVOTDEF tdp);
-//TDBPIVOT(PTDBPIVOT tdbp);
// Implementation
virtual AMT GetAmType(void) {return TYPE_AM_PIVOT;}
-//virtual PTDB Duplicate(PGLOBAL g) {return (PTDB)new(g) TDBPIVOT(this);}
-// void SetTdbp(PTDB tdbp) {Tdbp = tdbp;}
// Methods
-//virtual PTDB CopyOne(PTABS t);
virtual int GetRecpos(void) {return N;}
virtual void ResetDB(void) {N = 0;}
virtual int RowNumber(PGLOBAL g, bool b = FALSE);
@@ -84,22 +76,17 @@ class TDBPIVOT : public TDBPRX {
virtual int DeleteDB(PGLOBAL g, int irc);
virtual void CloseDB(PGLOBAL g);
- // The sorting function
-//virtual int Qcompare(int *, int *);
-
protected:
- bool GetSourceTable(PGLOBAL g);
-//int MakePivotColumns(PGLOBAL g);
-//bool UpdateTableFields(PGLOBAL g, int n);
+ // Internal routines
+ bool GetSourceTable(PGLOBAL g);
+ bool MakePivotColumns(PGLOBAL g);
+ bool MakeViewColumns(PGLOBAL g);
// Members
-//MYSQLC Myc; // MySQL connection class
-//PTDBQRS Tqrp; // To the source table result
char *Host; // Host machine to use
char *User; // User logon info
char *Pwd; // Password logon info
char *Database; // Database to be used by server
-//PQRYRES Qryp; // Points to Query result block
char *Tabname; // Name of source table
char *Tabsrc; // SQL of source table
char *Picol; // Pivot column name
@@ -108,9 +95,6 @@ class TDBPIVOT : public TDBPRX {
PCOL Fcolp; // To the function column in source
PCOL Xcolp; // To the pivot column in source
PCOL Dcolp; // To the dump column
-//PCOLRES Xresp; // To the pivot result column
-//PCOLRES To_Sort; // Saved Qryp To_Sort pointer
-//PVBLK Rblkp; // The value block of the pivot column
bool GBdone; // True when subtable is "Group by"
bool Accept; // TRUE if no match is accepted
int Mult; // Multiplication factor
@@ -168,75 +152,4 @@ class SRCCOL : public PRXCOL {
SRCCOL(void) {}
// Members
-//PVAL Cnval;
}; // end of class SRCCOL
-
-/***********************************************************************/
-/* TDBQRS: This is the Access Method class declaration for the Query */
-/* Result stored in memory in the current work area (volatil). */
-/***********************************************************************/
-class DllExport TDBQRS : public TDBASE {
- friend class QRSCOL;
- public:
- // Constructor
- TDBQRS(PQRYRES qrp) : TDBASE() {Qrp = qrp; CurPos = 0;}
- TDBQRS(PTDBQRS tdbp);
-
- // Implementation
- virtual AMT GetAmType(void) {return TYPE_AM_QRS;}
- virtual PTDB Duplicate(PGLOBAL g)
- {return (PTDB)new(g) TDBQRS(this);}
- PQRYRES GetQrp(void) {return Qrp;}
-
- // Methods
- virtual PTDB CopyOne(PTABS t);
- virtual int RowNumber(PGLOBAL g, BOOL b = FALSE);
- virtual int GetRecpos(void);
-//virtual PCATLG GetCat(void);
-//virtual PSZ GetPath(void);
- virtual int GetBadLines(void) {return Qrp->BadLines;}
-
- // Database routines
- virtual PCOL ColDB(PGLOBAL g, PSZ name, int num);
- virtual int GetMaxSize(PGLOBAL g);
- virtual bool OpenDB(PGLOBAL g);
- virtual int ReadDB(PGLOBAL g);
- virtual int WriteDB(PGLOBAL g);
- virtual int DeleteDB(PGLOBAL g, int irc);
- virtual void CloseDB(PGLOBAL g);
-
- private:
- TDBQRS(void) : TDBASE() {} // Standard constructor not to be used
-
- protected:
- // Members
- PQRYRES Qrp; // Points to Query Result block
- int CurPos; // Current line position
- }; // end of class TDBQRS
-
-/***********************************************************************/
-/* Class QRSCOL: QRS access method column descriptor. */
-/***********************************************************************/
-class DllExport QRSCOL : public COLBLK {
- friend class TDBQRS;
- public:
- // Constructors
- QRSCOL(PGLOBAL g, PCOLRES crp, PTDB tdbp, PCOL cprec, int i);
- QRSCOL(QRSCOL *colp, PTDB tdbp); // Constructor used in copy process
-
- // Implementation
- virtual int GetAmType(void) {return TYPE_AM_QRS;}
- PCOLRES GetCrp(void) {return Crp;}
- void *GetQrsData(void) {return Crp->Kdata;}
-
- // Methods
- virtual void ReadColumn(PGLOBAL g);
- virtual void Print(PGLOBAL g, FILE *, uint);
-
- protected:
- QRSCOL(void) {} // Default constructor not to be used
-
- // Members
- PCOLRES Crp;
- }; // end of class QRSCOL
-
diff --git a/storage/connect/tabtbl.cpp b/storage/connect/tabtbl.cpp
index 7e89cccf583..43fbb27a715 100644
--- a/storage/connect/tabtbl.cpp
+++ b/storage/connect/tabtbl.cpp
@@ -216,7 +216,7 @@ bool TDBTBL::InitTableList(PGLOBAL g)
{
int n;
PTABLE tp, tabp;
- PTDB tdbp;
+ PTDBASE tdbp;
PCOL colp;
PTBLDEF tdp = (PTBLDEF)To_Def;
@@ -252,7 +252,7 @@ bool TDBTBL::InitTableList(PGLOBAL g)
n++;
} // endif filp
- } // endfor tblp
+ } // endfor tp
//NumTables = n;
To_Filter = NULL; // To avoid doing it several times
diff --git a/storage/connect/tabutil.cpp b/storage/connect/tabutil.cpp
index c55b8d1fa5c..8698d4697b7 100644
--- a/storage/connect/tabutil.cpp
+++ b/storage/connect/tabutil.cpp
@@ -90,20 +90,21 @@ TABLE_SHARE *GetTableShare(PGLOBAL g, THD *thd, const char *db,
// 1 2 4 8
//flags = GTS_TABLE | GTS_VIEW | GTS_NOLOCK | GTS_FORCE_DISCOVERY;
- if (!open_table_def(thd, s, GTS_TABLE)) {
-#ifdef DBUG_OFF
- if (stricmp(s->db_plugin->name.str, "connect")) {
-#else
- if (stricmp((*s->db_plugin)->name.str, "connect")) {
-#endif
+ if (!open_table_def(thd, s, GTS_TABLE | GTS_VIEW)) {
+ if (!s->is_view) {
+ if (stricmp(plugin_name(s->db_plugin)->str, "connect")) {
#if defined(MYSQL_SUPPORT)
- mysql = true;
+ mysql = true;
#else // !MYSQL_SUPPORT
- sprintf(g->Message, "%s.%s is not a CONNECT table", db, name);
- return NULL;
+ sprintf(g->Message, "%s.%s is not a CONNECT table", db, name);
+ return NULL;
#endif // MYSQL_SUPPORT
- } else
- mysql = false;
+ } else
+ mysql = false;
+
+ } else {
+ mysql = true;
+ } // endif is_view
} else {
sprintf(g->Message, "Error %d opening share\n", s->error);
@@ -139,9 +140,12 @@ PQRYRES TabColumns(PGLOBAL g, THD *thd, const char *db,
PCOLRES crp;
if (!info) {
- if (!(s = GetTableShare(g, thd, db, name, mysql)))
+ if (!(s = GetTableShare(g, thd, db, name, mysql))) {
return NULL;
- else
+ } else if (s->is_view) {
+ strcpy(g->Message, "Cannot retreive Proxy columns from a view");
+ return NULL;
+ } else
n = s->fieldnames.count;
} else {
@@ -257,23 +261,27 @@ PRXDEF::PRXDEF(void)
/***********************************************************************/
bool PRXDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
{
- char *pn, *db, *tab;
+ char *pn, *db, *tab, *def = NULL;
db = Cat->GetStringCatInfo(g, "Dbname", "*");
+ def = Cat->GetStringCatInfo(g, "Srcdef", NULL);
if (!(tab = Cat->GetStringCatInfo(g, "Tabname", NULL))) {
- strcpy(g->Message, "Missing object table name");
- return TRUE;
- } // endif tab
+ if (!def) {
+ strcpy(g->Message, "Missing object table definition");
+ return TRUE;
+ } else
+ tab = "Noname";
- // Analyze the table name, it may have the format: [dbname.]tabname
- if ((pn = strchr(tab, '.'))) {
- *pn++ = 0;
- db = tab;
- tab = pn;
- } // endif pn
+ } else
+ // Analyze the table name, it may have the format: [dbname.]tabname
+ if ((pn = strchr(tab, '.'))) {
+ *pn++ = 0;
+ db = tab;
+ tab = pn;
+ } // endif pn
- Tablep = new(g) XTAB(tab);
+ Tablep = new(g) XTAB(tab, def);
Tablep->SetQualifier(db);
return FALSE;
} // end of DefineAM
@@ -303,12 +311,13 @@ TDBPRX::TDBPRX(PPRXDEF tdp) : TDBASE(tdp)
/***********************************************************************/
/* Get the PTDB of the sub-table. */
/***********************************************************************/
-PTDB TDBPRX::GetSubTable(PGLOBAL g, PTABLE tabp)
+PTDBASE TDBPRX::GetSubTable(PGLOBAL g, PTABLE tabp, bool b)
{
char *db, *name;
- bool mysql;
+ bool mysql = true;
PTDB tdbp = NULL;
- TABLE_SHARE *s;
+ TABLE_SHARE *s = NULL;
+ Field* *fp;
PCATLG cat = To_Def->GetCat();
PHC hc = ((MYCAT*)cat)->GetHandler();
LPCSTR cdb, curdb = hc->GetDBName(NULL);
@@ -328,10 +337,20 @@ PTDB TDBPRX::GetSubTable(PGLOBAL g, PTABLE tabp)
} // endfor tp
- if (!(s = GetTableShare(g, thd, db, name, mysql)))
- return NULL;
+ if (!tabp->GetSrc()) {
+ if (!(s = GetTableShare(g, thd, db, name, mysql)))
+ return NULL;
+
+ if (s->is_view && !b)
+ s->field = hc->get_table()->s->field;
- hc->tshp = s;
+ hc->tshp = s;
+ } else if (b) {
+ // Don't use caller's columns
+ fp = hc->get_table()->field;
+ hc->get_table()->field = NULL;
+ hc->get_table()->s->option_struct->srcdef = tabp->GetSrc();
+ } // endif srcdef
if (mysql) {
#if defined(MYSQL_SUPPORT)
@@ -355,15 +374,23 @@ PTDB TDBPRX::GetSubTable(PGLOBAL g, PTABLE tabp)
tdbp = cat->GetTable(g, tabp);
} // endif mysql
- hc->tshp = NULL;
+ if (s) {
+ if (s->is_view && !b)
+ s->field = NULL;
+
+ hc->tshp = NULL;
+ } else if (b)
+ hc->get_table()->field = fp;
if (trace && tdbp)
htrc("Subtable %s in %s\n",
name, SVP(((PTDBASE)tdbp)->GetDef()->GetDB()));
err:
- free_table_share(s);
- return tdbp;
+ if (s)
+ free_table_share(s);
+
+ return (PTDBASE)tdbp;
} // end of GetSubTable
/***********************************************************************/
@@ -373,7 +400,7 @@ bool TDBPRX::InitTable(PGLOBAL g)
{
if (!Tdbp) {
// Get the table description block of this table
- if (!(Tdbp = (PTDBASE)GetSubTable(g, ((PPRXDEF)To_Def)->Tablep)))
+ if (!(Tdbp = GetSubTable(g, ((PPRXDEF)To_Def)->Tablep)))
return TRUE;
} // endif Tdbp
diff --git a/storage/connect/tabutil.h b/storage/connect/tabutil.h
index 81e2a44464a..a6b08bce3d4 100644
--- a/storage/connect/tabutil.h
+++ b/storage/connect/tabutil.h
@@ -78,7 +78,7 @@ class DllExport TDBPRX : public TDBASE {
virtual int WriteDB(PGLOBAL g);
virtual int DeleteDB(PGLOBAL g, int irc);
virtual void CloseDB(PGLOBAL g) {if (Tdbp) Tdbp->CloseDB(g);}
- PTDB GetSubTable(PGLOBAL g, PTABLE tabp);
+ PTDBASE GetSubTable(PGLOBAL g, PTABLE tabp, bool b = false);
void RemoveNext(PTABLE tp);
protected:
@@ -93,6 +93,7 @@ class DllExport TDBPRX : public TDBASE {
class DllExport PRXCOL : public COLBLK {
friend class TDBPRX;
friend class TDBTBL;
+ friend class TDBOCCUR;
public:
// Constructors
PRXCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am = "PRX");
diff --git a/storage/connect/xtable.h b/storage/connect/xtable.h
index 8475c46d52d..7ef2d26136c 100644
--- a/storage/connect/xtable.h
+++ b/storage/connect/xtable.h
@@ -173,6 +173,7 @@ class DllExport TDBASE : public TDB {
virtual int GetRecpos(void) = 0;
virtual bool SetRecpos(PGLOBAL g, int recpos);
virtual bool IsReadOnly(void) {return Read_Only;}
+ virtual bool IsView(void) {return FALSE;}
virtual CHARSET_INFO *data_charset()
{
/*