Commit 39750cd4 authored by Olivier Bertrand's avatar Olivier Bertrand

- FIX a bug causing libxml2 not retrieving expanded multiple column values.

  This was working but the cause probably comes from freeing Xop object to
  handle memory leaks reported by Valgrind.
  Also add a test case on XML multiple tables.
added:
  storage/connect/mysql-test/connect/r/xml_mult.result
  storage/connect/mysql-test/connect/std_data/bookstore.xml
  storage/connect/mysql-test/connect/t/xml_mult.test
modified:
  storage/connect/domdoc.cpp
  storage/connect/tabxml.cpp
  storage/connect/tabxml.h

- Enhance the index types and flages returning functions.
modified:
  storage/connect/ha_connect.cc
  storage/connect/ha_connect.h

- Suppress irrelevant warning message (MDEV-6117)
modified:
  storage/connect/ha_connect.cc
parent 046ae9f5
...@@ -416,18 +416,24 @@ PXLIST DOMNODE::SelectNodes(PGLOBAL g, char *xp, PXLIST lp) ...@@ -416,18 +416,24 @@ PXLIST DOMNODE::SelectNodes(PGLOBAL g, char *xp, PXLIST lp)
/******************************************************************/ /******************************************************************/
PXNODE DOMNODE::SelectSingleNode(PGLOBAL g, char *xp, PXNODE np) PXNODE DOMNODE::SelectSingleNode(PGLOBAL g, char *xp, PXNODE np)
{ {
MSXML2::IXMLDOMNodePtr dnp = Nodep->selectSingleNode(xp); try {
MSXML2::IXMLDOMNodePtr dnp = Nodep->selectSingleNode(xp);
if (dnp) { if (dnp) {
if (np) { if (np) {
((PDOMNODE)np)->Nodep = dnp; ((PDOMNODE)np)->Nodep = dnp;
return np; return np;
} else } else
return new(g) DOMNODE(Doc, dnp); return new(g) DOMNODE(Doc, dnp);
} else } // endif dnp
return NULL;
} catch(_com_error e) {
sprintf(g->Message, "%s: %s", MSG(COM_ERROR),
_com_util::ConvertBSTRToString(e.Description()));
} catch(...) {}
return NULL;
} // end of SelectSingleNode } // end of SelectSingleNode
/******************************************************************/ /******************************************************************/
......
...@@ -621,7 +621,7 @@ TABTYPE ha_connect::GetRealType(PTOS pos) ...@@ -621,7 +621,7 @@ TABTYPE ha_connect::GetRealType(PTOS pos)
{ {
TABTYPE type; TABTYPE type;
if (pos || (pos= GetTableOptionStruct(table))) { if (pos || (pos= GetTableOptionStruct())) {
type= GetTypeID(pos->type); type= GetTypeID(pos->type);
if (type == TAB_UNDEF) if (type == TAB_UNDEF)
...@@ -633,6 +633,50 @@ TABTYPE ha_connect::GetRealType(PTOS pos) ...@@ -633,6 +633,50 @@ TABTYPE ha_connect::GetRealType(PTOS pos)
return type; return type;
} // end of GetRealType } // end of GetRealType
/** @brief
The name of the index type that will be used for display.
Don't implement this method unless you really have indexes.
*/
const char *ha_connect::index_type(uint inx)
{
switch (GetIndexType(GetRealType())) {
case 1: return "XPLUG";
case 2: return "REMOTE";
} // endswitch
return "Unknown";
} // end of index_type
/** @brief
This is a bitmap of flags that indicates how the storage engine
implements indexes. The current index flags are documented in
handler.h. If you do not implement indexes, just return zero here.
@details
part is the key part to check. First key part is 0.
If all_parts is set, MySQL wants to know the flags for the combined
index, up to and including 'part'.
*/
ulong ha_connect::index_flags(uint inx, uint part, bool all_parts) const
{
ulong flags= HA_READ_NEXT | HA_READ_RANGE |
HA_KEYREAD_ONLY | HA_KEY_SCAN_NOT_ROR;
ha_connect *hp= (ha_connect*)this;
PTOS pos= hp->GetTableOptionStruct();
if (pos) {
TABTYPE type= hp->GetRealType(pos);
switch (GetIndexType(type)) {
case 1: flags|= (HA_READ_ORDER | HA_READ_PREV); break;
case 2: flags|= HA_READ_AFTER_KEY; break;
} // endswitch
} // endif pos
return flags;
} // end of index_flags
/** @brief /** @brief
This is a list of flags that indicate what functionality the storage This is a list of flags that indicate what functionality the storage
engine implements. The current table flags are documented in handler.h engine implements. The current table flags are documented in handler.h
...@@ -641,14 +685,14 @@ ulonglong ha_connect::table_flags() const ...@@ -641,14 +685,14 @@ ulonglong ha_connect::table_flags() const
{ {
ulonglong flags= HA_CAN_VIRTUAL_COLUMNS | HA_REC_NOT_IN_SEQ | ulonglong flags= HA_CAN_VIRTUAL_COLUMNS | HA_REC_NOT_IN_SEQ |
HA_NO_AUTO_INCREMENT | HA_NO_PREFIX_CHAR_KEYS | HA_NO_AUTO_INCREMENT | HA_NO_PREFIX_CHAR_KEYS |
// HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE | HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE |
HA_PARTIAL_COLUMN_READ | HA_FILE_BASED | HA_PARTIAL_COLUMN_READ | HA_FILE_BASED |
// HA_NULL_IN_KEY | not implemented yet // HA_NULL_IN_KEY | not implemented yet
// HA_FAST_KEY_READ | causes error when sorting (???) // HA_FAST_KEY_READ | causes error when sorting (???)
HA_NO_TRANSACTIONS | HA_DUPLICATE_KEY_NOT_IN_ORDER | HA_NO_TRANSACTIONS | HA_DUPLICATE_KEY_NOT_IN_ORDER |
HA_NO_BLOBS | HA_MUST_USE_TABLE_CONDITION_PUSHDOWN; HA_NO_BLOBS | HA_MUST_USE_TABLE_CONDITION_PUSHDOWN;
ha_connect *hp= (ha_connect*)this; ha_connect *hp= (ha_connect*)this;
PTOS pos= hp->GetTableOptionStruct(table); PTOS pos= hp->GetTableOptionStruct();
if (pos) { if (pos) {
TABTYPE type= hp->GetRealType(pos); TABTYPE type= hp->GetRealType(pos);
...@@ -719,10 +763,11 @@ char *GetListOption(PGLOBAL g, const char *opname, ...@@ -719,10 +763,11 @@ char *GetListOption(PGLOBAL g, const char *opname,
/****************************************************************************/ /****************************************************************************/
/* Return the table option structure. */ /* Return the table option structure. */
/****************************************************************************/ /****************************************************************************/
PTOS ha_connect::GetTableOptionStruct(TABLE *tab) PTOS ha_connect::GetTableOptionStruct(TABLE_SHARE *s)
{ {
return (tshp) ? tshp->option_struct : TABLE_SHARE *tsp= (tshp) ? tshp : (s) ? s : table_share;
(tab) ? tab->s->option_struct : NULL;
return (tsp) ? tsp->option_struct : NULL;
} // end of GetTableOptionStruct } // end of GetTableOptionStruct
/****************************************************************************/ /****************************************************************************/
...@@ -731,7 +776,7 @@ PTOS ha_connect::GetTableOptionStruct(TABLE *tab) ...@@ -731,7 +776,7 @@ PTOS ha_connect::GetTableOptionStruct(TABLE *tab)
char *ha_connect::GetStringOption(char *opname, char *sdef) char *ha_connect::GetStringOption(char *opname, char *sdef)
{ {
char *opval= NULL; char *opval= NULL;
PTOS options= GetTableOptionStruct(table); PTOS options= GetTableOptionStruct();
if (!options) if (!options)
; ;
...@@ -803,10 +848,10 @@ bool ha_connect::GetBooleanOption(char *opname, bool bdef) ...@@ -803,10 +848,10 @@ bool ha_connect::GetBooleanOption(char *opname, bool bdef)
{ {
bool opval= bdef; bool opval= bdef;
char *pv; char *pv;
PTOS options= GetTableOptionStruct(table); PTOS options= GetTableOptionStruct();
if (!stricmp(opname, "View")) if (!stricmp(opname, "View"))
opval= (tshp) ? tshp->is_view : table->s->is_view; opval= (tshp) ? tshp->is_view : table_share->is_view;
else if (!options) else if (!options)
; ;
else if (!stricmp(opname, "Mapped")) else if (!stricmp(opname, "Mapped"))
...@@ -834,7 +879,7 @@ bool ha_connect::GetBooleanOption(char *opname, bool bdef) ...@@ -834,7 +879,7 @@ bool ha_connect::GetBooleanOption(char *opname, bool bdef)
/****************************************************************************/ /****************************************************************************/
bool ha_connect::SetBooleanOption(char *opname, bool b) bool ha_connect::SetBooleanOption(char *opname, bool b)
{ {
PTOS options= GetTableOptionStruct(table); PTOS options= GetTableOptionStruct();
if (!options) if (!options)
return true; return true;
...@@ -854,7 +899,7 @@ int ha_connect::GetIntegerOption(char *opname) ...@@ -854,7 +899,7 @@ int ha_connect::GetIntegerOption(char *opname)
{ {
ulonglong opval= NO_IVAL; ulonglong opval= NO_IVAL;
char *pv; char *pv;
PTOS options= GetTableOptionStruct(table); PTOS options= GetTableOptionStruct();
if (!options) if (!options)
; ;
...@@ -891,7 +936,7 @@ int ha_connect::GetIntegerOption(char *opname) ...@@ -891,7 +936,7 @@ int ha_connect::GetIntegerOption(char *opname)
/****************************************************************************/ /****************************************************************************/
bool ha_connect::SetIntegerOption(char *opname, int n) bool ha_connect::SetIntegerOption(char *opname, int n)
{ {
PTOS options= GetTableOptionStruct(table); PTOS options= GetTableOptionStruct();
if (!options) if (!options)
return true; return true;
...@@ -1153,7 +1198,7 @@ const char *ha_connect::GetDBName(const char* name) ...@@ -1153,7 +1198,7 @@ const char *ha_connect::GetDBName(const char* name)
const char *ha_connect::GetTableName(void) const char *ha_connect::GetTableName(void)
{ {
return (tshp) ? tshp->table_name.str : table->s->table_name.str; return (tshp) ? tshp->table_name.str : table_share->table_name.str;
} // end of GetTableName } // end of GetTableName
#if 0 #if 0
...@@ -3310,7 +3355,7 @@ int ha_connect::external_lock(THD *thd, int lock_type) ...@@ -3310,7 +3355,7 @@ int ha_connect::external_lock(THD *thd, int lock_type)
int rc= 0; int rc= 0;
bool xcheck=false, cras= false; bool xcheck=false, cras= false;
MODE newmode; MODE newmode;
PTOS options= GetTableOptionStruct(table); PTOS options= GetTableOptionStruct();
PGLOBAL g= GetPlug(thd, xp); PGLOBAL g= GetPlug(thd, xp);
DBUG_ENTER("ha_connect::external_lock"); DBUG_ENTER("ha_connect::external_lock");
...@@ -4550,7 +4595,7 @@ int ha_connect::create(const char *name, TABLE *table_arg, ...@@ -4550,7 +4595,7 @@ int ha_connect::create(const char *name, TABLE *table_arg,
DBUG_ENTER("ha_connect::create"); DBUG_ENTER("ha_connect::create");
int sqlcom= thd_sql_command(table_arg->in_use); int sqlcom= thd_sql_command(table_arg->in_use);
PTOS options= GetTableOptionStruct(table_arg); PTOS options= GetTableOptionStruct(table_arg->s);
table= table_arg; // Used by called functions table= table_arg; // Used by called functions
...@@ -4885,7 +4930,7 @@ int ha_connect::create(const char *name, TABLE *table_arg, ...@@ -4885,7 +4930,7 @@ int ha_connect::create(const char *name, TABLE *table_arg,
} else } else
::close(h); ::close(h);
if (type == TAB_FMT || options->readonly) if ((type == TAB_FMT || options->readonly) && sqlcom == SQLCOM_CREATE_TABLE)
push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0,
"Congratulation, you just created a read-only void table!"); "Congratulation, you just created a read-only void table!");
...@@ -5123,7 +5168,6 @@ ha_connect::check_if_supported_inplace_alter(TABLE *altered_table, ...@@ -5123,7 +5168,6 @@ ha_connect::check_if_supported_inplace_alter(TABLE *altered_table,
int sqlcom= thd_sql_command(thd); int sqlcom= thd_sql_command(thd);
TABTYPE newtyp, type= TAB_UNDEF; TABTYPE newtyp, type= TAB_UNDEF;
HA_CREATE_INFO *create_info= ha_alter_info->create_info; HA_CREATE_INFO *create_info= ha_alter_info->create_info;
//PTOS pos= GetTableOptionStruct(table);
PTOS newopt, oldopt; PTOS newopt, oldopt;
xp= GetUser(thd, xp); xp= GetUser(thd, xp);
PGLOBAL g= xp->g; PGLOBAL g= xp->g;
......
...@@ -167,7 +167,7 @@ public: ...@@ -167,7 +167,7 @@ public:
static bool connect_end(void); static bool connect_end(void);
TABTYPE GetRealType(PTOS pos= NULL); TABTYPE GetRealType(PTOS pos= NULL);
char *GetStringOption(char *opname, char *sdef= NULL); char *GetStringOption(char *opname, char *sdef= NULL);
PTOS GetTableOptionStruct(TABLE *table_arg); PTOS GetTableOptionStruct(TABLE_SHARE *s= NULL);
bool GetBooleanOption(char *opname, bool bdef); bool GetBooleanOption(char *opname, bool bdef);
bool SetBooleanOption(char *opname, bool b); bool SetBooleanOption(char *opname, bool b);
int GetIntegerOption(char *opname); int GetIntegerOption(char *opname);
...@@ -210,7 +210,7 @@ public: ...@@ -210,7 +210,7 @@ public:
The name of the index type that will be used for display. The name of the index type that will be used for display.
Don't implement this method unless you really have indexes. Don't implement this method unless you really have indexes.
*/ */
const char *index_type(uint inx) { return "XPLUG"; } const char *index_type(uint inx);
/** @brief /** @brief
The file extensions. The file extensions.
...@@ -241,11 +241,7 @@ public: ...@@ -241,11 +241,7 @@ public:
If all_parts is set, MySQL wants to know the flags for the combined If all_parts is set, MySQL wants to know the flags for the combined
index, up to and including 'part'. index, up to and including 'part'.
*/ */
ulong index_flags(uint inx, uint part, bool all_parts) const ulong index_flags(uint inx, uint part, bool all_parts) const;
{
return HA_READ_NEXT | HA_READ_RANGE | HA_READ_ORDER |
HA_READ_PREV | HA_KEYREAD_ONLY | HA_KEY_SCAN_NOT_ROR;
} // end of index_flags
/** @brief /** @brief
unireg.cc will call max_supported_record_length(), max_supported_keys(), unireg.cc will call max_supported_record_length(), max_supported_keys(),
......
Warnings:
Warning 1105 No file name. Table will use t1.xml
SET NAMES utf8;
#
# Testing expanded values
#
CREATE TABLE `bookstore` (
`category` CHAR(16) NOT NULL FIELD_FORMAT='@',
`title` VARCHAR(50) NOT NULL,
`lang` char(2) NOT NULL FIELD_FORMAT='title/@',
`author` VARCHAR(24) NOT NULL,
`year` INT(4) NOT NULL,
`price` DOUBLE(8,2) NOT NULL)
ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='bookstore.xml' OPTION_LIST='expand=1,mulnode=author,limit=6,xmlsup=libxml2';
SELECT * FROM bookstore;
category title lang author year price
COOKING Everyday Italian en Giada De Laurentiis 2005 30.00
CHILDREN Harry Potter en J K. Rowling 2005 29.99
WEB XQuery Kick Start en James McGovern 2003 49.99
WEB XQuery Kick Start en Per Bothner 2003 49.99
WEB XQuery Kick Start en Kurt Cagle 2003 49.99
WEB XQuery Kick Start en James Linn 2003 49.99
WEB XQuery Kick Start en Vaidyanathan Nagarajan 2003 49.99
WEB Learning XML en Erik T. Ray 2003 39.95
SELECT category, title, price FROM bookstore;
category title price
COOKING Everyday Italian 30.00
CHILDREN Harry Potter 29.99
WEB XQuery Kick Start 49.99
WEB Learning XML 39.95
SELECT category, title, author, price FROM bookstore WHERE author LIKE '%K%';
category title author price
CHILDREN Harry Potter J K. Rowling 29.99
WEB XQuery Kick Start Kurt Cagle 49.99
WEB Learning XML Erik T. Ray 39.95
SELECT category, title, price FROM bookstore WHERE author LIKE 'J%';
category title price
CHILDREN Harry Potter 29.99
WEB XQuery Kick Start 49.99
WEB XQuery Kick Start 49.99
#
# Limiting expanded values
#
ALTER TABLE bookstore OPTION_LIST='expand=1,mulnode=author,limit=3,xmlsup=libxml2';
SELECT * FROM bookstore;
category title lang author year price
COOKING Everyday Italian en Giada De Laurentiis 2005 30.00
CHILDREN Harry Potter en J K. Rowling 2005 29.99
WEB XQuery Kick Start en James McGovern 2003 49.99
WEB XQuery Kick Start en Per Bothner 2003 49.99
WEB XQuery Kick Start en Kurt Cagle 2003 49.99
WEB Learning XML en Erik T. Ray 2003 39.95
Warnings:
Warning 1105 Mutiple values limited to 3
# One line lost because the where clause is applied only on the first 3 rows
SELECT category, title, author, price FROM bookstore WHERE author LIKE 'J%';
category title author price
CHILDREN Harry Potter J K. Rowling 29.99
WEB XQuery Kick Start James McGovern 49.99
Warnings:
Warning 1105 Mutiple values limited to 3
#
# Testing concatenated values
#
ALTER TABLE bookstore OPTION_LIST='mulnode=author,limit=6,xmlsup=libxml2';
# truncated
SELECT * FROM bookstore;
category title lang author year price
COOKING Everyday Italian en Giada De Laurentiis 2005 30.00
CHILDREN Harry Potter en J K. Rowling 2005 29.99
WEB XQuery Kick Start en James McGovern, Per Both 2003 49.99
WEB Learning XML en Erik T. Ray 2003 39.95
Warnings:
Warning 1105 Truncated author content
# increase author size
ALTER TABLE bookstore MODIFY `author` VARCHAR(128) NOT NULL;
SELECT * FROM bookstore;
category title lang author year price
COOKING Everyday Italian en Giada De Laurentiis 2005 30.00
CHILDREN Harry Potter en J K. Rowling 2005 29.99
WEB XQuery Kick Start en James McGovern, Per Bothner, Kurt Cagle, James Linn, Vaidyanathan Nagarajan 2003 49.99
WEB Learning XML en Erik T. Ray 2003 39.95
#
# Limiting concatenated values
#
ALTER TABLE bookstore OPTION_LIST='mulnode=author,limit=4,xmlsup=libxml2';
SELECT * FROM bookstore;
category title lang author year price
COOKING Everyday Italian en Giada De Laurentiis 2005 30.00
CHILDREN Harry Potter en J K. Rowling 2005 29.99
WEB XQuery Kick Start en James McGovern, Per Bothner, Kurt Cagle, James Linn 2003 49.99
WEB Learning XML en Erik T. Ray 2003 39.95
Warnings:
Warning 1105 Mutiple values limited to 4
# The where clause is applied on the concatenated column result
SELECT category, title, author, price FROM bookstore WHERE author LIKE 'J%';
category title author price
CHILDREN Harry Potter J K. Rowling 29.99
WEB XQuery Kick Start James McGovern, Per Bothner, Kurt Cagle, James Linn 49.99
Warnings:
Warning 1105 Mutiple values limited to 4
DROP TABLE bookstore;
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
<book category="COOKING">
<title lang="en">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
<book category="CHILDREN">
<title lang="en">Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
<book category="WEB">
<title lang="en">XQuery Kick Start</title>
<author>James McGovern</author>
<author>Per Bothner</author>
<author>Kurt Cagle</author>
<author>James Linn</author>
<author>Vaidyanathan Nagarajan</author>
<year>2003</year>
<price>49.99</price>
</book>
<book category="WEB">
<title lang="en">Learning XML</title>
<author>Erik T. Ray</author>
<year>2003</year>
<price>39.95</price>
</book>
</bookstore>
--source have_libxml2.inc
let $MYSQLD_DATADIR= `select @@datadir`;
SET NAMES utf8;
--copy_file $MTR_SUITE_DIR/std_data/bookstore.xml $MYSQLD_DATADIR/test/bookstore.xml
#--echo $MYSQL_TEST_DIR
#--exec pwd
#SELECT LOAD_FILE('test/bookstore.xml');
--echo #
--echo # Testing expanded values
--echo #
CREATE TABLE `bookstore` (
`category` CHAR(16) NOT NULL FIELD_FORMAT='@',
`title` VARCHAR(50) NOT NULL,
`lang` char(2) NOT NULL FIELD_FORMAT='title/@',
`author` VARCHAR(24) NOT NULL,
`year` INT(4) NOT NULL,
`price` DOUBLE(8,2) NOT NULL)
ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='bookstore.xml' OPTION_LIST='expand=1,mulnode=author,limit=6,xmlsup=libxml2';
SELECT * FROM bookstore;
SELECT category, title, price FROM bookstore;
SELECT category, title, author, price FROM bookstore WHERE author LIKE '%K%';
SELECT category, title, price FROM bookstore WHERE author LIKE 'J%';
--echo #
--echo # Limiting expanded values
--echo #
ALTER TABLE bookstore OPTION_LIST='expand=1,mulnode=author,limit=3,xmlsup=libxml2';
SELECT * FROM bookstore;
--echo # One line lost because the where clause is applied only on the first 3 rows
SELECT category, title, author, price FROM bookstore WHERE author LIKE 'J%';
--echo #
--echo # Testing concatenated values
--echo #
ALTER TABLE bookstore OPTION_LIST='mulnode=author,limit=6,xmlsup=libxml2';
--echo # truncated
SELECT * FROM bookstore;
--echo # increase author size
ALTER TABLE bookstore MODIFY `author` VARCHAR(128) NOT NULL;
SELECT * FROM bookstore;
--echo #
--echo # Limiting concatenated values
--echo #
ALTER TABLE bookstore OPTION_LIST='mulnode=author,limit=4,xmlsup=libxml2';
SELECT * FROM bookstore;
--echo # The where clause is applied on the concatenated column result
SELECT category, title, author, price FROM bookstore WHERE author LIKE 'J%';
DROP TABLE bookstore;
#
# Clean up
#
--remove_file $MYSQLD_DATADIR/test/bookstore.xml
...@@ -145,7 +145,7 @@ bool XMLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) ...@@ -145,7 +145,7 @@ bool XMLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
XmlDB = GetStringCatInfo(g, "XmlDB", ""); XmlDB = GetStringCatInfo(g, "XmlDB", "");
Nslist = GetStringCatInfo(g, "Nslist", ""); Nslist = GetStringCatInfo(g, "Nslist", "");
DefNs = GetStringCatInfo(g, "DefNs", ""); DefNs = GetStringCatInfo(g, "DefNs", "");
Limit = GetIntCatInfo("Limit", 2); Limit = GetIntCatInfo("Limit", 10);
Xpand = (GetIntCatInfo("Expand", 0) != 0); Xpand = (GetIntCatInfo("Expand", 0) != 0);
Header = GetIntCatInfo("Header", 0); Header = GetIntCatInfo("Header", 0);
GetCharCatInfo("Xmlsup", "*", buf, sizeof(buf)); GetCharCatInfo("Xmlsup", "*", buf, sizeof(buf));
...@@ -1038,12 +1038,13 @@ XMLCOL::XMLCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am) ...@@ -1038,12 +1038,13 @@ XMLCOL::XMLCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am)
Type = Tdbp->Coltype; Type = Tdbp->Coltype;
Nx = -1; Nx = -1;
Sx = -1; Sx = -1;
N = 0;
Valbuf = NULL; Valbuf = NULL;
To_Val = NULL; To_Val = NULL;
} // end of XMLCOL constructor } // end of XMLCOL constructor
/***********************************************************************/ /***********************************************************************/
/* XMLCOL constructor used for copying columns. */ /* XMLCOL constructor used for copying columns. */
/* tdbp is the pointer to the new table descriptor. */ /* tdbp is the pointer to the new table descriptor. */
/***********************************************************************/ /***********************************************************************/
XMLCOL::XMLCOL(XMLCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp) XMLCOL::XMLCOL(XMLCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
...@@ -1068,6 +1069,7 @@ XMLCOL::XMLCOL(XMLCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp) ...@@ -1068,6 +1069,7 @@ XMLCOL::XMLCOL(XMLCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
Rank = col1->Rank; Rank = col1->Rank;
Nx = col1->Nx; Nx = col1->Nx;
Sx = col1->Sx; Sx = col1->Sx;
N = col1->N;
Type = col1->Type; Type = col1->Type;
To_Val = col1->To_Val; To_Val = col1->To_Val;
} // end of XMLCOL copy constructor } // end of XMLCOL copy constructor
...@@ -1080,8 +1082,8 @@ bool XMLCOL::AllocBuf(PGLOBAL g, bool mode) ...@@ -1080,8 +1082,8 @@ bool XMLCOL::AllocBuf(PGLOBAL g, bool mode)
if (Valbuf) if (Valbuf)
return false; // Already done return false; // Already done
Valbuf = (char*)PlugSubAlloc(g, NULL, Long + 1); //Valbuf = (char*)PlugSubAlloc(g, NULL, Long + 1);
Valbuf[Long] = '\0'; //Valbuf[Long] = '\0';
return ParseXpath(g, mode); return ParseXpath(g, mode);
} // end of AllocBuf } // end of AllocBuf
...@@ -1095,7 +1097,7 @@ bool XMLCOL::AllocBuf(PGLOBAL g, bool mode) ...@@ -1095,7 +1097,7 @@ bool XMLCOL::AllocBuf(PGLOBAL g, bool mode)
bool XMLCOL::ParseXpath(PGLOBAL g, bool mode) bool XMLCOL::ParseXpath(PGLOBAL g, bool mode)
{ {
char *p, *p2, *pbuf = NULL; char *p, *p2, *pbuf = NULL;
int i, len = strlen(Name); int i, n = 1, len = strlen(Name);
len += ((Tdbp->Colname) ? strlen(Tdbp->Colname) : 0); len += ((Tdbp->Colname) ? strlen(Tdbp->Colname) : 0);
len += ((Xname) ? strlen(Xname) : 0); len += ((Xname) ? strlen(Xname) : 0);
...@@ -1122,7 +1124,7 @@ bool XMLCOL::ParseXpath(PGLOBAL g, bool mode) ...@@ -1122,7 +1124,7 @@ bool XMLCOL::ParseXpath(PGLOBAL g, bool mode)
// For Update or Insert the Xpath must be analyzed // For Update or Insert the Xpath must be analyzed
if (mode) { if (mode) {
for (i = 0, p = pbuf; (p = strchr(p, '/')); i++, p++) for (i = 0, p = pbuf; (p = strchr(p, '/')); i++, p++)
Nod++; // One path node found Nod++; // One path node found
if (Nod) if (Nod)
Nodes = (char**)PlugSubAlloc(g, NULL, Nod * sizeof(char*)); Nodes = (char**)PlugSubAlloc(g, NULL, Nod * sizeof(char*));
...@@ -1136,7 +1138,7 @@ bool XMLCOL::ParseXpath(PGLOBAL g, bool mode) ...@@ -1136,7 +1138,7 @@ bool XMLCOL::ParseXpath(PGLOBAL g, bool mode)
strcpy(g->Message, MSG(CONCAT_SUBNODE)); strcpy(g->Message, MSG(CONCAT_SUBNODE));
return true; return true;
} else } else
Inod = i; // Index of multiple node Inod = i; // Index of multiple node
if (mode) { if (mode) {
// For Update or Insert the Xpath must be explicit // For Update or Insert the Xpath must be explicit
...@@ -1171,7 +1173,7 @@ bool XMLCOL::ParseXpath(PGLOBAL g, bool mode) ...@@ -1171,7 +1173,7 @@ bool XMLCOL::ParseXpath(PGLOBAL g, bool mode)
} else if (Type == 2) { } else if (Type == 2) {
// HTML like table, columns are retrieved by position // HTML like table, columns are retrieved by position
new(this) XPOSCOL(Value); // Change the class of this column new(this) XPOSCOL(Value); // Change the class of this column
Tdbp->Hasnod = true; Tdbp->Hasnod = true;
return false; return false;
} else if (Type == 0 && !mode) { } else if (Type == 0 && !mode) {
...@@ -1185,9 +1187,18 @@ bool XMLCOL::ParseXpath(PGLOBAL g, bool mode) ...@@ -1185,9 +1187,18 @@ bool XMLCOL::ParseXpath(PGLOBAL g, bool mode)
if (Inod >= 0) { if (Inod >= 0) {
Tdbp->Colp = this; // To force expand Tdbp->Colp = this; // To force expand
new(this) XMULCOL(Value); // Change the class of this column
if (Tdbp->Xpand)
n = Tdbp->Limit;
new(this) XMULCOL(Value); // Change the class of this column
} // endif Inod } // endif Inod
Valbuf = (char*)PlugSubAlloc(g, NULL, n * (Long + 1));
for (i = 0; i < n; i++)
Valbuf[Long + (i * (Long + 1))] = '\0';
if (Type || Nod) if (Type || Nod)
Tdbp->Hasnod = true; Tdbp->Hasnod = true;
...@@ -1470,60 +1481,72 @@ void XMLCOL::WriteColumn(PGLOBAL g) ...@@ -1470,60 +1481,72 @@ void XMLCOL::WriteColumn(PGLOBAL g)
void XMULCOL::ReadColumn(PGLOBAL g) void XMULCOL::ReadColumn(PGLOBAL g)
{ {
char *p; char *p;
int i, n, len; int i, len;
bool b = Tdbp->Xpand;
if (Nx != Tdbp->Irow) // New row if (Nx != Tdbp->Irow) { // New row
Nl = Tdbp->RowNode->SelectNodes(g, Xname, Nl); Nl = Tdbp->RowNode->SelectNodes(g, Xname, Nl);
else if (Sx == Tdbp->Nsub)
return; // Same row
if ((n = Nl->GetLength())) { if ((N = Nl->GetLength())) {
*(p = Valbuf) = '\0'; *(p = Valbuf) = '\0';
len = Long; len = Long;
for (i = Tdbp->Nsub; i < n; i++) { if (N > Tdbp->Limit) {
ValNode = Nl->GetItem(g, i, Vxnp); N = Tdbp->Limit;
sprintf(g->Message, "Mutiple values limited to %d", Tdbp->Limit);
PushWarning(g, Tdbp);
} // endif N
if (ValNode->GetType() != XML_ELEMENT_NODE && for (i = 0; i < N; i++) {
ValNode->GetType() != XML_ATTRIBUTE_NODE) { ValNode = Nl->GetItem(g, i, Vxnp);
sprintf(g->Message, MSG(BAD_VALNODE), ValNode->GetType(), Name);
longjmp(g->jumper[g->jump_level], TYPE_AM_XML);
} // endif type
// Get the Xname value from the XML file if (ValNode->GetType() != XML_ELEMENT_NODE &&
switch (ValNode->GetContent(g, p, len + 1)) { ValNode->GetType() != XML_ATTRIBUTE_NODE) {
case RC_OK: sprintf(g->Message, MSG(BAD_VALNODE), ValNode->GetType(), Name);
break;
case RC_INFO:
PushWarning(g, Tdbp);
break;
default:
longjmp(g->jumper[g->jump_level], TYPE_AM_XML); longjmp(g->jumper[g->jump_level], TYPE_AM_XML);
} // endswitch } // endif type
if (!Tdbp->Xpand) { // Get the Xname value from the XML file
// Concatenate all values switch (ValNode->GetContent(g, p, (b ? Long : len))) {
if (n - i > 1) case RC_OK:
strncat(Valbuf, ", ", Long + 1); break;
case RC_INFO:
len -= strlen(p); PushWarning(g, Tdbp);
p += strlen(p); break;
} else default:
break; longjmp(g->jumper[g->jump_level], TYPE_AM_XML);
} // endswitch
} // endfor i
if (!b) {
// Concatenate all values
if (N - i > 1)
strncat(Valbuf, ", ", len - strlen(p));
if ((len -= strlen(p)) <= 0)
break;
p += strlen(p);
} else // Xpand
p += (Long + 1);
} // endfor i
Value->SetValue_psz(Valbuf);
} else {
if (Nullable)
Value->SetNull(true);
Value->SetValue_psz(Valbuf); Value->Reset(); // Null value
} else { } // endif ValNode
if (Nullable)
Value->SetNull(true);
Value->Reset(); // Null value } else if (Sx == Tdbp->Nsub)
} // endif ValNode return; // Same row
else // Expanded value
Value->SetValue_psz(Valbuf + (Tdbp->Nsub * (Long + 1)));
Nx = Tdbp->Irow; Nx = Tdbp->Irow;
Sx = Tdbp->Nsub; Sx = Tdbp->Nsub;
Tdbp->NextSame = (Tdbp->Xpand && Nl->GetLength() - Sx > 1); Tdbp->NextSame = (Tdbp->Xpand && N - Sx > 1);
} // end of ReadColumn } // end of ReadColumn
/***********************************************************************/ /***********************************************************************/
......
...@@ -190,6 +190,7 @@ class XMLCOL : public COLBLK { ...@@ -190,6 +190,7 @@ class XMLCOL : public COLBLK {
int Long; // Buffer length int Long; // Buffer length
int Nx; // The last read row int Nx; // The last read row
int Sx; // The last read sub-row int Sx; // The last read sub-row
int N; // The number of (multiple) values
PVAL To_Val; // To value used for Update/Insert PVAL To_Val; // To value used for Update/Insert
}; // end of class XMLCOL }; // end of class XMLCOL
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment