You've already forked mariadb-columnstore-engine
mirror of
https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
synced 2025-07-29 08:21:15 +03:00
MCOL-1482 An UPDATE operation on a non-ColumnStore table involving a
cross-engine join with a ColumnStore table errors out. ColumnStore cannot directly update a foreign table. We detect whether a multi-table UPDATE operation is performed on a foreign table, if so, do not create the select_handler and let the server execute the UPDATE operation instead.
This commit is contained in:
@ -6325,6 +6325,48 @@ bool isMCSTable(TABLE* table_ptr)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isForeignTableUpdate(THD* thd)
|
||||||
|
{
|
||||||
|
LEX* lex = thd->lex;
|
||||||
|
|
||||||
|
if (lex->sql_command != SQLCOM_UPDATE_MULTI)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Item_field* item;
|
||||||
|
List_iterator_fast<Item> field_it(lex->first_select_lex()->item_list);
|
||||||
|
|
||||||
|
while ((item = (Item_field*) field_it++))
|
||||||
|
{
|
||||||
|
if (item->field && item->field->table && !isMCSTable(item->field->table))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function is different from isForeignTableUpdate()
|
||||||
|
// above as it only checks if any of the tables involved
|
||||||
|
// in the multi-table update statement is a foreign table,
|
||||||
|
// irrespective of whether the update is performed on the
|
||||||
|
// foreign table or not, as in isForeignTableUpdate().
|
||||||
|
bool isUpdateHasForeignTable(THD* thd)
|
||||||
|
{
|
||||||
|
LEX* lex = thd->lex;
|
||||||
|
|
||||||
|
if (lex->sql_command != SQLCOM_UPDATE_MULTI)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
TABLE_LIST* table_ptr = lex->first_select_lex()->get_table_list();
|
||||||
|
|
||||||
|
for (; table_ptr; table_ptr = table_ptr->next_local)
|
||||||
|
{
|
||||||
|
if (table_ptr->table && !isMCSTable(table_ptr->table))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/*@brief set some runtime params to run the query */
|
/*@brief set some runtime params to run the query */
|
||||||
/***********************************************************
|
/***********************************************************
|
||||||
* DESCRIPTION:
|
* DESCRIPTION:
|
||||||
@ -6576,10 +6618,7 @@ int processWhere(SELECT_LEX &select_lex,
|
|||||||
else if (select_lex.where)
|
else if (select_lex.where)
|
||||||
icp = select_lex.where;
|
icp = select_lex.where;
|
||||||
}
|
}
|
||||||
else if (!join && ( ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE ) ||
|
else if (!join && isUpdateOrDeleteStatement(gwi.thd->lex->sql_command))
|
||||||
((gwi.thd->lex)->sql_command == SQLCOM_DELETE ) ||
|
|
||||||
((gwi.thd->lex)->sql_command == SQLCOM_UPDATE_MULTI ) ||
|
|
||||||
((gwi.thd->lex)->sql_command == SQLCOM_DELETE_MULTI )))
|
|
||||||
{
|
{
|
||||||
isUpdateDelete = true;
|
isUpdateDelete = true;
|
||||||
}
|
}
|
||||||
@ -7392,7 +7431,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex,
|
|||||||
}
|
}
|
||||||
|
|
||||||
//@Bug 3030 Add error check for dml statement
|
//@Bug 3030 Add error check for dml statement
|
||||||
if ( ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE ) || ((gwi.thd->lex)->sql_command == SQLCOM_DELETE ) || ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE_MULTI ) || ((gwi.thd->lex)->sql_command == SQLCOM_DELETE_MULTI ) )
|
if (isUpdateOrDeleteStatement(gwi.thd->lex->sql_command))
|
||||||
{
|
{
|
||||||
if ( after_size - before_size != 0 )
|
if ( after_size - before_size != 0 )
|
||||||
{
|
{
|
||||||
@ -7426,7 +7465,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex,
|
|||||||
case REAL_RESULT:
|
case REAL_RESULT:
|
||||||
case TIME_RESULT:
|
case TIME_RESULT:
|
||||||
{
|
{
|
||||||
if ( ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE ) || ((gwi.thd->lex)->sql_command == SQLCOM_DELETE ) || ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE_MULTI ) || ((gwi.thd->lex)->sql_command == SQLCOM_DELETE_MULTI ))
|
if (isUpdateOrDeleteStatement(gwi.thd->lex->sql_command))
|
||||||
{ }
|
{ }
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -7458,7 +7497,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex,
|
|||||||
|
|
||||||
case Item::NULL_ITEM:
|
case Item::NULL_ITEM:
|
||||||
{
|
{
|
||||||
if ( ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE ) || ((gwi.thd->lex)->sql_command == SQLCOM_DELETE ) || ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE_MULTI ) || ((gwi.thd->lex)->sql_command == SQLCOM_DELETE_MULTI ) )
|
if (isUpdateOrDeleteStatement(gwi.thd->lex->sql_command))
|
||||||
{ }
|
{ }
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -9258,7 +9297,7 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro
|
|||||||
}
|
}
|
||||||
|
|
||||||
//@Bug 3030 Add error check for dml statement
|
//@Bug 3030 Add error check for dml statement
|
||||||
if ( ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE ) || ((gwi.thd->lex)->sql_command == SQLCOM_DELETE ) || ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE_MULTI ) || ((gwi.thd->lex)->sql_command == SQLCOM_DELETE_MULTI ) )
|
if (isUpdateOrDeleteStatement(gwi.thd->lex->sql_command))
|
||||||
{
|
{
|
||||||
if ( after_size - before_size != 0 )
|
if ( after_size - before_size != 0 )
|
||||||
{
|
{
|
||||||
@ -9289,7 +9328,7 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro
|
|||||||
case REAL_RESULT:
|
case REAL_RESULT:
|
||||||
case TIME_RESULT:
|
case TIME_RESULT:
|
||||||
{
|
{
|
||||||
if ( ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE ) || ((gwi.thd->lex)->sql_command == SQLCOM_DELETE ) || ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE_MULTI ) || ((gwi.thd->lex)->sql_command == SQLCOM_DELETE_MULTI ))
|
if (isUpdateOrDeleteStatement(gwi.thd->lex->sql_command))
|
||||||
{ }
|
{ }
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -9321,7 +9360,7 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro
|
|||||||
|
|
||||||
case Item::NULL_ITEM:
|
case Item::NULL_ITEM:
|
||||||
{
|
{
|
||||||
if ( ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE ) || ((gwi.thd->lex)->sql_command == SQLCOM_DELETE ) || ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE_MULTI ) || ((gwi.thd->lex)->sql_command == SQLCOM_DELETE_MULTI ) )
|
if (isUpdateOrDeleteStatement(gwi.thd->lex->sql_command))
|
||||||
{ }
|
{ }
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -854,7 +854,7 @@ uint32_t doUpdateDelete(THD* thd, gp_walk_info& gwi, const std::vector<COND*>& c
|
|||||||
{
|
{
|
||||||
Message::Args args;
|
Message::Args args;
|
||||||
|
|
||||||
if (((thd->lex)->sql_command == SQLCOM_UPDATE) || ((thd->lex)->sql_command == SQLCOM_UPDATE_MULTI))
|
if (isUpdateStatement(thd->lex->sql_command))
|
||||||
args.add("Update");
|
args.add("Update");
|
||||||
#if 0
|
#if 0
|
||||||
else if (thd->rgi_slave && thd->rgi_slave->m_table_map.count() != 0)
|
else if (thd->rgi_slave && thd->rgi_slave->m_table_map.count() != 0)
|
||||||
@ -909,7 +909,7 @@ uint32_t doUpdateDelete(THD* thd, gp_walk_info& gwi, const std::vector<COND*>& c
|
|||||||
updateCP->isDML(true);
|
updateCP->isDML(true);
|
||||||
|
|
||||||
//@Bug 2753. the memory already freed by destructor of UpdateSqlStatement
|
//@Bug 2753. the memory already freed by destructor of UpdateSqlStatement
|
||||||
if (((thd->lex)->sql_command == SQLCOM_UPDATE) || ((thd->lex)->sql_command == SQLCOM_UPDATE_MULTI))
|
if (isUpdateStatement(thd->lex->sql_command))
|
||||||
{
|
{
|
||||||
ColumnAssignment* columnAssignmentPtr;
|
ColumnAssignment* columnAssignmentPtr;
|
||||||
Item_field* item;
|
Item_field* item;
|
||||||
@ -1202,8 +1202,7 @@ uint32_t doUpdateDelete(THD* thd, gp_walk_info& gwi, const std::vector<COND*>& c
|
|||||||
|
|
||||||
// Exit early if there is nothing to update
|
// Exit early if there is nothing to update
|
||||||
if (colAssignmentListPtr->empty() &&
|
if (colAssignmentListPtr->empty() &&
|
||||||
(((thd->lex)->sql_command == SQLCOM_UPDATE) ||
|
isUpdateStatement(thd->lex->sql_command))
|
||||||
((thd->lex)->sql_command == SQLCOM_UPDATE_MULTI)))
|
|
||||||
{
|
{
|
||||||
ci->affectedRows = 0;
|
ci->affectedRows = 0;
|
||||||
return 0;
|
return 0;
|
||||||
@ -1216,7 +1215,7 @@ uint32_t doUpdateDelete(THD* thd, gp_walk_info& gwi, const std::vector<COND*>& c
|
|||||||
CalpontSystemCatalog::TableName aTableName;
|
CalpontSystemCatalog::TableName aTableName;
|
||||||
TABLE_LIST* first_table = 0;
|
TABLE_LIST* first_table = 0;
|
||||||
|
|
||||||
if (( (thd->lex)->sql_command == SQLCOM_UPDATE ) || ( (thd->lex)->sql_command == SQLCOM_UPDATE_MULTI ) )
|
if (isUpdateStatement(thd->lex->sql_command))
|
||||||
{
|
{
|
||||||
aTableName.schema = schemaName;
|
aTableName.schema = schemaName;
|
||||||
aTableName.table = tableName;
|
aTableName.table = tableName;
|
||||||
@ -1238,10 +1237,10 @@ uint32_t doUpdateDelete(THD* thd, gp_walk_info& gwi, const std::vector<COND*>& c
|
|||||||
IDEBUG( cout << "STMT: " << dmlStmt << " and sessionID " << thd->thread_id << endl );
|
IDEBUG( cout << "STMT: " << dmlStmt << " and sessionID " << thd->thread_id << endl );
|
||||||
VendorDMLStatement dmlStatement(dmlStmt, sessionID);
|
VendorDMLStatement dmlStatement(dmlStmt, sessionID);
|
||||||
|
|
||||||
if (( (thd->lex)->sql_command == SQLCOM_UPDATE ) || ( (thd->lex)->sql_command == SQLCOM_UPDATE_MULTI ) )
|
if (isUpdateStatement(thd->lex->sql_command))
|
||||||
dmlStatement.set_DMLStatementType( DML_UPDATE );
|
dmlStatement.set_DMLStatementType(DML_UPDATE);
|
||||||
else
|
else
|
||||||
dmlStatement.set_DMLStatementType( DML_DELETE );
|
dmlStatement.set_DMLStatementType(DML_DELETE);
|
||||||
|
|
||||||
TableName* qualifiedTablName = new TableName();
|
TableName* qualifiedTablName = new TableName();
|
||||||
|
|
||||||
@ -1249,7 +1248,7 @@ uint32_t doUpdateDelete(THD* thd, gp_walk_info& gwi, const std::vector<COND*>& c
|
|||||||
//@Bug 2753. To make sure the momory is freed.
|
//@Bug 2753. To make sure the momory is freed.
|
||||||
updateStmt.fColAssignmentListPtr = colAssignmentListPtr;
|
updateStmt.fColAssignmentListPtr = colAssignmentListPtr;
|
||||||
|
|
||||||
if (( (thd->lex)->sql_command == SQLCOM_UPDATE ) || ( (thd->lex)->sql_command == SQLCOM_UPDATE_MULTI ) )
|
if (isUpdateStatement(thd->lex->sql_command))
|
||||||
{
|
{
|
||||||
qualifiedTablName->fName = tableName;
|
qualifiedTablName->fName = tableName;
|
||||||
qualifiedTablName->fSchema = schemaName;
|
qualifiedTablName->fSchema = schemaName;
|
||||||
@ -1343,7 +1342,7 @@ uint32_t doUpdateDelete(THD* thd, gp_walk_info& gwi, const std::vector<COND*>& c
|
|||||||
List<Item> items;
|
List<Item> items;
|
||||||
SELECT_LEX select_lex;
|
SELECT_LEX select_lex;
|
||||||
|
|
||||||
if (( (thd->lex)->sql_command == SQLCOM_UPDATE ) || ( (thd->lex)->sql_command == SQLCOM_UPDATE_MULTI ) )
|
if (isUpdateStatement(thd->lex->sql_command))
|
||||||
{
|
{
|
||||||
items = (thd->lex->first_select_lex()->item_list);
|
items = (thd->lex->first_select_lex()->item_list);
|
||||||
thd->lex->first_select_lex()->item_list = thd->lex->value_list;
|
thd->lex->first_select_lex()->item_list = thd->lex->value_list;
|
||||||
@ -1492,7 +1491,7 @@ uint32_t doUpdateDelete(THD* thd, gp_walk_info& gwi, const std::vector<COND*>& c
|
|||||||
returnedCols.push_back((updateCP->columnMap()).begin()->second);
|
returnedCols.push_back((updateCP->columnMap()).begin()->second);
|
||||||
|
|
||||||
//@Bug 6123. get the correct returned columnlist
|
//@Bug 6123. get the correct returned columnlist
|
||||||
if (( (thd->lex)->sql_command == SQLCOM_DELETE ) || ( (thd->lex)->sql_command == SQLCOM_DELETE_MULTI ) )
|
if (isDeleteStatement(thd->lex->sql_command))
|
||||||
{
|
{
|
||||||
returnedCols.clear();
|
returnedCols.clear();
|
||||||
//choose the smallest column to project
|
//choose the smallest column to project
|
||||||
@ -1543,7 +1542,7 @@ uint32_t doUpdateDelete(THD* thd, gp_walk_info& gwi, const std::vector<COND*>& c
|
|||||||
|
|
||||||
updateCP->returnedCols( returnedCols );
|
updateCP->returnedCols( returnedCols );
|
||||||
|
|
||||||
if (( (thd->lex)->sql_command == SQLCOM_UPDATE ) || ( (thd->lex)->sql_command == SQLCOM_UPDATE_MULTI ) )
|
if (isUpdateStatement(thd->lex->sql_command))
|
||||||
{
|
{
|
||||||
const ParseTree* ptsub = updateCP->filters();
|
const ParseTree* ptsub = updateCP->filters();
|
||||||
|
|
||||||
@ -1561,8 +1560,7 @@ uint32_t doUpdateDelete(THD* thd, gp_walk_info& gwi, const std::vector<COND*>& c
|
|||||||
ptsub->walk(makeUpdateSemiJoin, &tbList[0] );
|
ptsub->walk(makeUpdateSemiJoin, &tbList[0] );
|
||||||
}
|
}
|
||||||
|
|
||||||
if (( (thd->lex)->sql_command == SQLCOM_UPDATE ) || ( (thd->lex)->sql_command == SQLCOM_UPDATE_MULTI ) )
|
thd->lex->first_select_lex()->item_list = items;
|
||||||
thd->lex->first_select_lex()->item_list = items;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -2039,10 +2037,7 @@ int ha_mcs::impl_rnd_init(TABLE* table, const std::vector<COND*>& condStack)
|
|||||||
UPDATE innotab1 SET a=100 WHERE a NOT IN (SELECT a FROM cstab1 WHERE a=1);
|
UPDATE innotab1 SET a=100 WHERE a NOT IN (SELECT a FROM cstab1 WHERE a=1);
|
||||||
*/
|
*/
|
||||||
if (!isReadOnly() && // make sure the current table is being modified
|
if (!isReadOnly() && // make sure the current table is being modified
|
||||||
(thd->lex->sql_command == SQLCOM_UPDATE ||
|
isUpdateOrDeleteStatement(thd->lex->sql_command))
|
||||||
thd->lex->sql_command == SQLCOM_DELETE ||
|
|
||||||
thd->lex->sql_command == SQLCOM_DELETE_MULTI ||
|
|
||||||
thd->lex->sql_command == SQLCOM_UPDATE_MULTI))
|
|
||||||
return doUpdateDelete(thd, gwi, condStack);
|
return doUpdateDelete(thd, gwi, condStack);
|
||||||
|
|
||||||
uint32_t sessionID = tid2sid(thd->thread_id);
|
uint32_t sessionID = tid2sid(thd->thread_id);
|
||||||
@ -2372,8 +2367,10 @@ int ha_mcs_impl_rnd_next(uchar* buf, TABLE* table)
|
|||||||
thd->lex->sql_command == SQLCOM_LOAD))
|
thd->lex->sql_command == SQLCOM_LOAD))
|
||||||
return HA_ERR_END_OF_FILE;
|
return HA_ERR_END_OF_FILE;
|
||||||
|
|
||||||
if (((thd->lex)->sql_command == SQLCOM_UPDATE) || ((thd->lex)->sql_command == SQLCOM_DELETE) ||
|
if ((thd->lex->sql_command == SQLCOM_UPDATE) ||
|
||||||
((thd->lex)->sql_command == SQLCOM_DELETE_MULTI) || ((thd->lex)->sql_command == SQLCOM_UPDATE_MULTI))
|
(thd->lex->sql_command == SQLCOM_DELETE) ||
|
||||||
|
(thd->lex->sql_command == SQLCOM_DELETE_MULTI) ||
|
||||||
|
((thd->lex->sql_command == SQLCOM_UPDATE_MULTI) && !isForeignTableUpdate(thd)))
|
||||||
return HA_ERR_END_OF_FILE;
|
return HA_ERR_END_OF_FILE;
|
||||||
|
|
||||||
// @bug 2547
|
// @bug 2547
|
||||||
@ -2461,22 +2458,15 @@ int ha_mcs_impl_rnd_end(TABLE* table, bool is_pushdown_hand)
|
|||||||
thd->lex->sql_command == SQLCOM_LOAD))
|
thd->lex->sql_command == SQLCOM_LOAD))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
||||||
// MCOL-2178 isUnion member only assigned, never used
|
|
||||||
// if (is_pushdown_hand)
|
|
||||||
// {
|
|
||||||
// MIGR::infinidb_vtable.isUnion = false;
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (get_fe_conn_info_ptr() != NULL)
|
if (get_fe_conn_info_ptr() != NULL)
|
||||||
ci = reinterpret_cast<cal_connection_info*>(get_fe_conn_info_ptr());
|
ci = reinterpret_cast<cal_connection_info*>(get_fe_conn_info_ptr());
|
||||||
if ( (thd->lex)->sql_command == SQLCOM_ALTER_TABLE )
|
if ( (thd->lex)->sql_command == SQLCOM_ALTER_TABLE )
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
if (((thd->lex)->sql_command == SQLCOM_UPDATE) ||
|
if ((thd->lex->sql_command == SQLCOM_UPDATE) ||
|
||||||
((thd->lex)->sql_command == SQLCOM_DELETE) ||
|
(thd->lex->sql_command == SQLCOM_DELETE) ||
|
||||||
((thd->lex)->sql_command == SQLCOM_DELETE_MULTI) ||
|
(thd->lex->sql_command == SQLCOM_DELETE_MULTI) ||
|
||||||
((thd->lex)->sql_command == SQLCOM_UPDATE_MULTI))
|
((thd->lex->sql_command == SQLCOM_UPDATE_MULTI) && !isForeignTableUpdate(thd)))
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
if (!ci)
|
if (!ci)
|
||||||
@ -3668,10 +3658,7 @@ COND* ha_mcs_impl_cond_push(COND* cond, TABLE* table, std::vector<COND*>& condSt
|
|||||||
{
|
{
|
||||||
THD* thd = current_thd;
|
THD* thd = current_thd;
|
||||||
|
|
||||||
if (((thd->lex)->sql_command == SQLCOM_UPDATE) ||
|
if (isUpdateOrDeleteStatement(thd->lex->sql_command))
|
||||||
((thd->lex)->sql_command == SQLCOM_UPDATE_MULTI) ||
|
|
||||||
((thd->lex)->sql_command == SQLCOM_DELETE) ||
|
|
||||||
((thd->lex)->sql_command == SQLCOM_DELETE_MULTI))
|
|
||||||
{
|
{
|
||||||
condStack.push_back(cond);
|
condStack.push_back(cond);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -3921,7 +3908,6 @@ int ha_mcs_impl_group_by_init(mcs_handler_info *handler_info, TABLE* table)
|
|||||||
|
|
||||||
idbassert(ci != 0);
|
idbassert(ci != 0);
|
||||||
|
|
||||||
|
|
||||||
if (thd->killed == KILL_QUERY || thd->killed == KILL_QUERY_HARD)
|
if (thd->killed == KILL_QUERY || thd->killed == KILL_QUERY_HARD)
|
||||||
{
|
{
|
||||||
force_close_fep_conn(thd, ci);
|
force_close_fep_conn(thd, ci);
|
||||||
@ -4326,15 +4312,12 @@ int ha_mcs_impl_group_by_next(TABLE* table)
|
|||||||
{
|
{
|
||||||
THD* thd = current_thd;
|
THD* thd = current_thd;
|
||||||
|
|
||||||
if (((thd->lex)->sql_command == SQLCOM_UPDATE) || ((thd->lex)->sql_command == SQLCOM_DELETE) ||
|
if ((thd->lex->sql_command == SQLCOM_UPDATE) ||
|
||||||
((thd->lex)->sql_command == SQLCOM_DELETE_MULTI) || ((thd->lex)->sql_command == SQLCOM_UPDATE_MULTI))
|
(thd->lex->sql_command == SQLCOM_DELETE) ||
|
||||||
|
(thd->lex->sql_command == SQLCOM_DELETE_MULTI) ||
|
||||||
|
(thd->lex->sql_command == SQLCOM_UPDATE_MULTI && !isForeignTableUpdate(thd)))
|
||||||
return HA_ERR_END_OF_FILE;
|
return HA_ERR_END_OF_FILE;
|
||||||
|
|
||||||
// @bug 2547
|
|
||||||
// MCOL-2178
|
|
||||||
// if (MIGR::infinidb_vtable.impossibleWhereOnUnion)
|
|
||||||
// return HA_ERR_END_OF_FILE;
|
|
||||||
|
|
||||||
if (get_fe_conn_info_ptr() == nullptr)
|
if (get_fe_conn_info_ptr() == nullptr)
|
||||||
set_fe_conn_info_ptr((void*)new cal_connection_info());
|
set_fe_conn_info_ptr((void*)new cal_connection_info());
|
||||||
|
|
||||||
@ -4426,9 +4409,6 @@ int ha_mcs_impl_group_by_end(TABLE* table)
|
|||||||
thd->lex->sql_command == SQLCOM_LOAD))
|
thd->lex->sql_command == SQLCOM_LOAD))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// MCOL-2178 isUnion member only assigned, never used
|
|
||||||
// MIGR::infinidb_vtable.isUnion = false;
|
|
||||||
|
|
||||||
if (get_fe_conn_info_ptr() != NULL)
|
if (get_fe_conn_info_ptr() != NULL)
|
||||||
ci = reinterpret_cast<cal_connection_info*>(get_fe_conn_info_ptr());
|
ci = reinterpret_cast<cal_connection_info*>(get_fe_conn_info_ptr());
|
||||||
|
|
||||||
@ -4638,8 +4618,8 @@ int ha_mcs_impl_pushdown_init(mcs_handler_info* handler_info, TABLE* table)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// MCOL-4023 We need to test this code path.
|
// MCOL-4023 We need to test this code path.
|
||||||
//Update and delete code
|
// Update and delete code
|
||||||
if ( ((thd->lex)->sql_command == SQLCOM_UPDATE) || ((thd->lex)->sql_command == SQLCOM_DELETE) || ((thd->lex)->sql_command == SQLCOM_DELETE_MULTI) || ((thd->lex)->sql_command == SQLCOM_UPDATE_MULTI))
|
if (isUpdateOrDeleteStatement(thd->lex->sql_command))
|
||||||
return doUpdateDelete(thd, gwi, std::vector<COND*>());
|
return doUpdateDelete(thd, gwi, std::vector<COND*>());
|
||||||
|
|
||||||
uint32_t sessionID = tid2sid(thd->thread_id);
|
uint32_t sessionID = tid2sid(thd->thread_id);
|
||||||
@ -5059,8 +5039,7 @@ int ha_mcs_impl_select_next(uchar* buf, TABLE* table)
|
|||||||
thd->lex->sql_command == SQLCOM_LOAD))
|
thd->lex->sql_command == SQLCOM_LOAD))
|
||||||
return HA_ERR_END_OF_FILE;
|
return HA_ERR_END_OF_FILE;
|
||||||
|
|
||||||
if (((thd->lex)->sql_command == SQLCOM_UPDATE) || ((thd->lex)->sql_command == SQLCOM_DELETE) ||
|
if (isUpdateOrDeleteStatement(thd->lex->sql_command))
|
||||||
((thd->lex)->sql_command == SQLCOM_DELETE_MULTI) || ((thd->lex)->sql_command == SQLCOM_UPDATE_MULTI))
|
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
// @bug 2547
|
// @bug 2547
|
||||||
|
@ -366,6 +366,8 @@ void gp_walk(const Item* item, void* arg);
|
|||||||
void parse_item (Item* item, std::vector<Item_field*>& field_vec, bool& hasNonSupportItem, uint16& parseInfo, gp_walk_info* gwip = NULL);
|
void parse_item (Item* item, std::vector<Item_field*>& field_vec, bool& hasNonSupportItem, uint16& parseInfo, gp_walk_info* gwip = NULL);
|
||||||
const std::string bestTableName(const Item_field* ifp);
|
const std::string bestTableName(const Item_field* ifp);
|
||||||
bool isMCSTable(TABLE* table_ptr);
|
bool isMCSTable(TABLE* table_ptr);
|
||||||
|
bool isForeignTableUpdate(THD* thd);
|
||||||
|
bool isUpdateHasForeignTable(THD* thd);
|
||||||
|
|
||||||
// execution plan util functions prototypes
|
// execution plan util functions prototypes
|
||||||
execplan::ReturnedColumn* buildReturnedColumn(Item* item, gp_walk_info& gwi, bool& nonSupport, bool isRefItem = false);
|
execplan::ReturnedColumn* buildReturnedColumn(Item* item, gp_walk_info& gwi, bool& nonSupport, bool isRefItem = false);
|
||||||
@ -409,6 +411,24 @@ bool buildEqualityPredicate(execplan::ReturnedColumn* lhs,
|
|||||||
const std::vector<Item*>& itemList,
|
const std::vector<Item*>& itemList,
|
||||||
bool isInSubs = false);
|
bool isInSubs = false);
|
||||||
|
|
||||||
|
inline bool isUpdateStatement(const enum_sql_command& command)
|
||||||
|
{
|
||||||
|
return (command == SQLCOM_UPDATE) ||
|
||||||
|
(command == SQLCOM_UPDATE_MULTI);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool isDeleteStatement(const enum_sql_command& command)
|
||||||
|
{
|
||||||
|
return (command == SQLCOM_DELETE) ||
|
||||||
|
(command == SQLCOM_DELETE_MULTI);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool isUpdateOrDeleteStatement(const enum_sql_command& command)
|
||||||
|
{
|
||||||
|
return isUpdateStatement(command) ||
|
||||||
|
isDeleteStatement(command);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_WALK_COND
|
#ifdef DEBUG_WALK_COND
|
||||||
void debug_walk(const Item* item, void* arg);
|
void debug_walk(const Item* item, void* arg);
|
||||||
#endif
|
#endif
|
||||||
|
@ -498,6 +498,13 @@ create_columnstore_derived_handler(THD* thd, TABLE_LIST *table_ptr)
|
|||||||
if (thd->stmt_arena && thd->stmt_arena->is_stmt_execute())
|
if (thd->stmt_arena && thd->stmt_arena->is_stmt_execute())
|
||||||
return handler;
|
return handler;
|
||||||
|
|
||||||
|
// MCOL-1482 Disable derived_handler if the multi-table update
|
||||||
|
// statement contains a non-columnstore table.
|
||||||
|
if (cal_impl_if::isUpdateHasForeignTable(thd))
|
||||||
|
{
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
|
||||||
SELECT_LEX_UNIT *unit = table_ptr->derived;
|
SELECT_LEX_UNIT *unit = table_ptr->derived;
|
||||||
SELECT_LEX *sl = unit->first_select();
|
SELECT_LEX *sl = unit->first_select();
|
||||||
|
|
||||||
@ -754,6 +761,14 @@ create_columnstore_select_handler(THD* thd, SELECT_LEX* select_lex)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MCOL-1482 Disable select_handler for a multi-table update
|
||||||
|
// with a non-columnstore table as the target table of the update
|
||||||
|
// operation.
|
||||||
|
if (cal_impl_if::isForeignTableUpdate(thd))
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// Flag to indicate if this is a prepared statement
|
// Flag to indicate if this is a prepared statement
|
||||||
bool isPS = thd->stmt_arena && thd->stmt_arena->is_stmt_execute();
|
bool isPS = thd->stmt_arena && thd->stmt_arena->is_stmt_execute();
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ GRANT ALL PRIVILEGES ON *.* TO 'cejuser'@'localhost';
|
|||||||
FLUSH PRIVILEGES;
|
FLUSH PRIVILEGES;
|
||||||
CREATE TABLE t1 (t1_int INT, t1_char CHAR(5))ENGINE=Innodb;
|
CREATE TABLE t1 (t1_int INT, t1_char CHAR(5))ENGINE=Innodb;
|
||||||
CREATE TABLE t2 (t2_int INT, t2_char CHAR(5))ENGINE=Columnstore;
|
CREATE TABLE t2 (t2_int INT, t2_char CHAR(5))ENGINE=Columnstore;
|
||||||
|
CREATE VIEW v1 AS SELECT * FROM t1;
|
||||||
INSERT INTO t1 VALUES (NULL,''),(1,'aaa'),(2,'bbb'),(3,'ccc'),(4,'ddd'),(5,'eee'),(6,'ffff'),(7,'ggggg');
|
INSERT INTO t1 VALUES (NULL,''),(1,'aaa'),(2,'bbb'),(3,'ccc'),(4,'ddd'),(5,'eee'),(6,'ffff'),(7,'ggggg');
|
||||||
INSERT INTO t2 VALUES (NULL,''),(1,'hhhh'),(3,'iii'),(5,'jjj'),(7,'kkkk'),(9,'lll'),(11,'m'),(13,'nnn');
|
INSERT INTO t2 VALUES (NULL,''),(1,'hhhh'),(3,'iii'),(5,'jjj'),(7,'kkkk'),(9,'lll'),(11,'m'),(13,'nnn');
|
||||||
SELECT * FROM t1, t2 WHERE t1.t1_int = t2.t2_int AND t1.t1_int = 3;
|
SELECT * FROM t1, t2 WHERE t1.t1_int = t2.t2_int AND t1.t1_int = 3;
|
||||||
@ -23,17 +24,38 @@ t1_int t1_char t2_int t2_char
|
|||||||
5 eee 5 sssss
|
5 eee 5 sssss
|
||||||
7 ggggg 7 sssss
|
7 ggggg 7 sssss
|
||||||
UPDATE t1 JOIN t2 on t1.t1_int=t2.t2_int SET t1.t1_char='s';
|
UPDATE t1 JOIN t2 on t1.t1_int=t2.t2_int SET t1.t1_char='s';
|
||||||
ERROR HY000: Internal error: IDB-2006: 'mcs45_db.t1' does not exist in Columnstore.
|
|
||||||
SELECT * FROM t1;
|
SELECT * FROM t1;
|
||||||
t1_int t1_char
|
t1_int t1_char
|
||||||
NULL
|
NULL
|
||||||
1 aaa
|
1 s
|
||||||
2 bbb
|
2 bbb
|
||||||
3 ccc
|
3 s
|
||||||
4 ddd
|
4 ddd
|
||||||
5 eee
|
5 s
|
||||||
6 ffff
|
6 ffff
|
||||||
7 ggggg
|
7 s
|
||||||
|
UPDATE v1 JOIN t2 on v1.t1_int=t2.t2_int SET v1.t1_char='t';
|
||||||
|
SELECT * FROM t1;
|
||||||
|
t1_int t1_char
|
||||||
|
NULL
|
||||||
|
1 t
|
||||||
|
2 bbb
|
||||||
|
3 t
|
||||||
|
4 ddd
|
||||||
|
5 t
|
||||||
|
6 ffff
|
||||||
|
7 t
|
||||||
|
UPDATE t1 JOIN (SELECT * FROM t2 WHERE t2_int < 5) d_t2 on t1.t1_int=d_t2.t2_int SET t1.t1_char='u';
|
||||||
|
SELECT * FROM t1;
|
||||||
|
t1_int t1_char
|
||||||
|
NULL
|
||||||
|
1 u
|
||||||
|
2 bbb
|
||||||
|
3 u
|
||||||
|
4 ddd
|
||||||
|
5 t
|
||||||
|
6 ffff
|
||||||
|
7 t
|
||||||
SELECT * FROM t2;
|
SELECT * FROM t2;
|
||||||
t2_int t2_char
|
t2_int t2_char
|
||||||
NULL NULL
|
NULL NULL
|
||||||
@ -48,13 +70,13 @@ DELETE t2 FROM t2 JOIN t1 ON t1.t1_int = t2.t2_int AND t1.t1_int = 7;
|
|||||||
SELECT * FROM t1;
|
SELECT * FROM t1;
|
||||||
t1_int t1_char
|
t1_int t1_char
|
||||||
NULL
|
NULL
|
||||||
1 aaa
|
1 u
|
||||||
2 bbb
|
2 bbb
|
||||||
3 ccc
|
3 u
|
||||||
4 ddd
|
4 ddd
|
||||||
5 eee
|
5 t
|
||||||
6 ffff
|
6 ffff
|
||||||
7 ggggg
|
7 t
|
||||||
SELECT * FROM t2;
|
SELECT * FROM t2;
|
||||||
t2_int t2_char
|
t2_int t2_char
|
||||||
NULL NULL
|
NULL NULL
|
||||||
@ -66,5 +88,21 @@ NULL NULL
|
|||||||
13 nnn
|
13 nnn
|
||||||
DELETE t1 FROM t1 JOIN t2 ON t1.t1_int = t2.t2_int AND t1.t1_int = 5;
|
DELETE t1 FROM t1 JOIN t2 ON t1.t1_int = t2.t2_int AND t1.t1_int = 5;
|
||||||
ERROR HY000: Internal error: IDB-2006: 'mcs45_db.t1' does not exist in Columnstore.
|
ERROR HY000: Internal error: IDB-2006: 'mcs45_db.t1' does not exist in Columnstore.
|
||||||
|
CREATE TABLE mcs(a INT, b INT)ENGINE=Columnstore;
|
||||||
|
CREATE TABLE idb(a INT, b INT)ENGINE=Innodb;
|
||||||
|
INSERT INTO mcs(a,b) VALUES (1,2),(2,3),(4,5);
|
||||||
|
INSERT INTO idb(a,b) VALUES (1,2),(2,3),(4,5);
|
||||||
|
UPDATE idb dest JOIN mcs src ON dest.a=src.a SET dest.b = dest.b + src.b + 100;
|
||||||
|
SELECT * FROM idb;
|
||||||
|
a b
|
||||||
|
1 104
|
||||||
|
2 106
|
||||||
|
4 110
|
||||||
|
UPDATE idb dest JOIN mcs src ON dest.a=src.a SET dest.b = dest.b + src.b + 100;
|
||||||
|
SELECT * FROM idb;
|
||||||
|
a b
|
||||||
|
1 206
|
||||||
|
2 209
|
||||||
|
4 215
|
||||||
DROP USER 'cejuser'@'localhost';
|
DROP USER 'cejuser'@'localhost';
|
||||||
DROP DATABASE mcs45_db;
|
DROP DATABASE mcs45_db;
|
||||||
|
@ -38,6 +38,7 @@ FLUSH PRIVILEGES;
|
|||||||
# Create tables with Innodb and Columnstore engines
|
# Create tables with Innodb and Columnstore engines
|
||||||
CREATE TABLE t1 (t1_int INT, t1_char CHAR(5))ENGINE=Innodb;
|
CREATE TABLE t1 (t1_int INT, t1_char CHAR(5))ENGINE=Innodb;
|
||||||
CREATE TABLE t2 (t2_int INT, t2_char CHAR(5))ENGINE=Columnstore;
|
CREATE TABLE t2 (t2_int INT, t2_char CHAR(5))ENGINE=Columnstore;
|
||||||
|
CREATE VIEW v1 AS SELECT * FROM t1;
|
||||||
INSERT INTO t1 VALUES (NULL,''),(1,'aaa'),(2,'bbb'),(3,'ccc'),(4,'ddd'),(5,'eee'),(6,'ffff'),(7,'ggggg');
|
INSERT INTO t1 VALUES (NULL,''),(1,'aaa'),(2,'bbb'),(3,'ccc'),(4,'ddd'),(5,'eee'),(6,'ffff'),(7,'ggggg');
|
||||||
INSERT INTO t2 VALUES (NULL,''),(1,'hhhh'),(3,'iii'),(5,'jjj'),(7,'kkkk'),(9,'lll'),(11,'m'),(13,'nnn');
|
INSERT INTO t2 VALUES (NULL,''),(1,'hhhh'),(3,'iii'),(5,'jjj'),(7,'kkkk'),(9,'lll'),(11,'m'),(13,'nnn');
|
||||||
|
|
||||||
@ -46,19 +47,36 @@ UPDATE t2, t1 SET t2.t2_char = 'zzz' WHERE t1.t1_int = t2.t2_int AND t1.t1_int =
|
|||||||
SELECT * FROM t1, t2 WHERE t1.t1_int = t2.t2_int AND t1.t1_int = 3;
|
SELECT * FROM t1, t2 WHERE t1.t1_int = t2.t2_int AND t1.t1_int = 3;
|
||||||
UPDATE t1 JOIN t2 on t1.t1_int=t2.t2_int SET t2.t2_char='sssss';
|
UPDATE t1 JOIN t2 on t1.t1_int=t2.t2_int SET t2.t2_char='sssss';
|
||||||
SELECT * FROM t1, t2 WHERE t1.t1_int = t2.t2_int;
|
SELECT * FROM t1, t2 WHERE t1.t1_int = t2.t2_int;
|
||||||
|
|
||||||
# MCOL-1482
|
# MCOL-1482
|
||||||
--error ER_INTERNAL_ERROR
|
|
||||||
UPDATE t1 JOIN t2 on t1.t1_int=t2.t2_int SET t1.t1_char='s';
|
UPDATE t1 JOIN t2 on t1.t1_int=t2.t2_int SET t1.t1_char='s';
|
||||||
|
SELECT * FROM t1;
|
||||||
|
# Update foreign view
|
||||||
|
UPDATE v1 JOIN t2 on v1.t1_int=t2.t2_int SET v1.t1_char='t';
|
||||||
|
SELECT * FROM t1;
|
||||||
|
# Update foreign table with a subquery as the source
|
||||||
|
UPDATE t1 JOIN (SELECT * FROM t2 WHERE t2_int < 5) d_t2 on t1.t1_int=d_t2.t2_int SET t1.t1_char='u';
|
||||||
|
|
||||||
SELECT * FROM t1;
|
SELECT * FROM t1;
|
||||||
SELECT * FROM t2;
|
SELECT * FROM t2;
|
||||||
DELETE t2 FROM t2 JOIN t1 ON t1.t1_int = t2.t2_int AND t1.t1_int = 7;
|
DELETE t2 FROM t2 JOIN t1 ON t1.t1_int = t2.t2_int AND t1.t1_int = 7;
|
||||||
SELECT * FROM t1;
|
SELECT * FROM t1;
|
||||||
SELECT * FROM t2;
|
SELECT * FROM t2;
|
||||||
# Similar error as MCOL-1482
|
# Similar error as MCOL-1482, but for a foreign engine DELETE.
|
||||||
--error ER_INTERNAL_ERROR
|
--error ER_INTERNAL_ERROR
|
||||||
DELETE t1 FROM t1 JOIN t2 ON t1.t1_int = t2.t2_int AND t1.t1_int = 5;
|
DELETE t1 FROM t1 JOIN t2 ON t1.t1_int = t2.t2_int AND t1.t1_int = 5;
|
||||||
|
|
||||||
|
# Test case from MCOL-1482 issue description
|
||||||
|
CREATE TABLE mcs(a INT, b INT)ENGINE=Columnstore;
|
||||||
|
CREATE TABLE idb(a INT, b INT)ENGINE=Innodb;
|
||||||
|
|
||||||
|
INSERT INTO mcs(a,b) VALUES (1,2),(2,3),(4,5);
|
||||||
|
INSERT INTO idb(a,b) VALUES (1,2),(2,3),(4,5);
|
||||||
|
UPDATE idb dest JOIN mcs src ON dest.a=src.a SET dest.b = dest.b + src.b + 100;
|
||||||
|
SELECT * FROM idb;
|
||||||
|
UPDATE idb dest JOIN mcs src ON dest.a=src.a SET dest.b = dest.b + src.b + 100;
|
||||||
|
SELECT * FROM idb;
|
||||||
|
|
||||||
# Clean UP
|
# Clean UP
|
||||||
DROP USER 'cejuser'@'localhost';
|
DROP USER 'cejuser'@'localhost';
|
||||||
DROP DATABASE mcs45_db;
|
DROP DATABASE mcs45_db;
|
||||||
|
Reference in New Issue
Block a user