diff --git a/CMakeLists.txt b/CMakeLists.txt index b931d30c0..3be90eaa4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -283,11 +283,13 @@ SET (ENGINE_WE_CONFIGCPP_INCLUDE "${CMAKE_CURRENT_SOURCE_DIR}/writeengine/x SET (ENGINE_SERVER_SQL_INCLUDE "${SERVER_SOURCE_ROOT_DIR}/sql") SET (ENGINE_SERVER_INCLUDE_INCLUDE "${SERVER_SOURCE_ROOT_DIR}/include") SET (ENGINE_SERVER_PCRE_INCLUDE "${SERVER_BUILD_INCLUDE_DIR}/../pcre") +SET (ENGINE_SERVER_WSREP_INCLUDE "${SERVER_BUILD_INCLUDE_DIR}/../wsrep-lib/include") +SET (ENGINE_SERVER_WSREP_API_INCLUDE "${SERVER_BUILD_INCLUDE_DIR}/../wsrep-lib/wsrep-API/v26/") SET (ENGINE_UTILS_UDFSDK_INCLUDE "${CMAKE_CURRENT_SOURCE_DIR}/utils/udfsdk") SET (ENGINE_DEFAULT_INCLUDES ${CMAKE_BINARY_DIR} "." "../" "../../" ${SERVER_BUILD_INCLUDE_DIR}) -SET (ENGINE_COMMON_INCLUDES ${ENGINE_DEFAULT_INCLUDES} ${Boost_INCLUDE_DIR} ${LIBXML2_INCLUDE_DIR} ${ENGINE_UTILS_MESSAGEQCPP_INCLUDE} ${ENGINE_WE_SHARED_INCLUDE} ${ENGINE_UTILS_IDBDATAFILE_INCLUDE} ${ENGINE_UTILS_LOGGINGCPP_INCLUDE} ${ENGINE_UTILS_CONFIGCPP_INCLUDE} ${ENGINE_UTILS_COMPRESS_INCLUDE} ${ENGINE_VERSIONING_BRM_INCLUDE} ${ENGINE_UTILS_ROWGROUP_INCLUDE} ${ENGINE_UTILS_COMMON_INCLUDE} ${ENGINE_UTILS_DATACONVERT_INCLUDE} ${ENGINE_UTILS_RWLOCK_INCLUDE} ${ENGINE_UTILS_FUNCEXP_INCLUDE} ${ENGINE_OAMAPPS_ALARMMANAGER_INCLUDE} ${ENGINE_UTILS_INCLUDE} ${ENGINE_OAM_OAMCPP_INCLUDE} ${ENGINE_DBCON_DDLPKGPROC_INCLUDE} ${ENGINE_DBCON_DDLPKG_INCLUDE} ${ENGINE_DBCON_EXECPLAN_INCLUDE} ${ENGINE_UTILS_STARTUP_INCLUDE} ${ENGINE_DBCON_JOBLIST_INCLUDE} ${ENGINE_WE_WRAPPER_INCLUDE} ${ENGINE_WE_SERVER_INCLUDE} ${ENGINE_DBCON_DMLPKG_INCLUDE} ${ENGINE_WE_CLIENT_INCLUDE} ${ENGINE_DBCON_DMLPKGPROC_INCLUDE} ${ENGINE_UTILS_CACHEUTILS_INCLUDE} ${ENGINE_UTILS_MYSQLCL_INCLUDE} ${ENGINE_UTILS_QUERYTELE_INCLUDE} ${ENGINE_UTILS_THRIFT_INCLUDE} ${ENGINE_UTILS_JOINER_INCLUDE} ${ENGINE_UTILS_THREADPOOL_INCLUDE} ${ENGINE_UTILS_BATCHLDR_INCLUDE} ${ENGINE_UTILS_DDLCLEANUP_INCLUDE} ${ENGINE_UTILS_QUERYSTATS_INCLUDE} ${ENGINE_WE_CONFIGCPP_INCLUDE} ${ENGINE_SERVER_SQL_INCLUDE} ${ENGINE_SERVER_INCLUDE_INCLUDE} ${ENGINE_SERVER_PCRE_INCLUDE} ${ENGINE_UTILS_UDFSDK_INCLUDE} ${ENGINE_UTILS_LIBMYSQL_CL_INCLUDE}) +SET (ENGINE_COMMON_INCLUDES ${ENGINE_DEFAULT_INCLUDES} ${Boost_INCLUDE_DIR} ${LIBXML2_INCLUDE_DIR} ${ENGINE_UTILS_MESSAGEQCPP_INCLUDE} ${ENGINE_WE_SHARED_INCLUDE} ${ENGINE_UTILS_IDBDATAFILE_INCLUDE} ${ENGINE_UTILS_LOGGINGCPP_INCLUDE} ${ENGINE_UTILS_CONFIGCPP_INCLUDE} ${ENGINE_UTILS_COMPRESS_INCLUDE} ${ENGINE_VERSIONING_BRM_INCLUDE} ${ENGINE_UTILS_ROWGROUP_INCLUDE} ${ENGINE_UTILS_COMMON_INCLUDE} ${ENGINE_UTILS_DATACONVERT_INCLUDE} ${ENGINE_UTILS_RWLOCK_INCLUDE} ${ENGINE_UTILS_FUNCEXP_INCLUDE} ${ENGINE_OAMAPPS_ALARMMANAGER_INCLUDE} ${ENGINE_UTILS_INCLUDE} ${ENGINE_OAM_OAMCPP_INCLUDE} ${ENGINE_DBCON_DDLPKGPROC_INCLUDE} ${ENGINE_DBCON_DDLPKG_INCLUDE} ${ENGINE_DBCON_EXECPLAN_INCLUDE} ${ENGINE_UTILS_STARTUP_INCLUDE} ${ENGINE_DBCON_JOBLIST_INCLUDE} ${ENGINE_WE_WRAPPER_INCLUDE} ${ENGINE_WE_SERVER_INCLUDE} ${ENGINE_DBCON_DMLPKG_INCLUDE} ${ENGINE_WE_CLIENT_INCLUDE} ${ENGINE_DBCON_DMLPKGPROC_INCLUDE} ${ENGINE_UTILS_CACHEUTILS_INCLUDE} ${ENGINE_UTILS_MYSQLCL_INCLUDE} ${ENGINE_UTILS_QUERYTELE_INCLUDE} ${ENGINE_UTILS_THRIFT_INCLUDE} ${ENGINE_UTILS_JOINER_INCLUDE} ${ENGINE_UTILS_THREADPOOL_INCLUDE} ${ENGINE_UTILS_BATCHLDR_INCLUDE} ${ENGINE_UTILS_DDLCLEANUP_INCLUDE} ${ENGINE_UTILS_QUERYSTATS_INCLUDE} ${ENGINE_WE_CONFIGCPP_INCLUDE} ${ENGINE_SERVER_SQL_INCLUDE} ${ENGINE_SERVER_INCLUDE_INCLUDE} ${ENGINE_SERVER_PCRE_INCLUDE} ${ENGINE_SERVER_WSREP_API_INCLUDE} ${ENGINE_SERVER_WSREP_INCLUDE} ${ENGINE_UTILS_UDFSDK_INCLUDE} ${ENGINE_UTILS_LIBMYSQL_CL_INCLUDE}) ADD_SUBDIRECTORY(utils) ADD_SUBDIRECTORY(oam/oamcpp) diff --git a/dbcon/ddlpackage/CMakeLists.txt b/dbcon/ddlpackage/CMakeLists.txt index 084aeeac0..8bdc68b1e 100644 --- a/dbcon/ddlpackage/CMakeLists.txt +++ b/dbcon/ddlpackage/CMakeLists.txt @@ -11,9 +11,6 @@ ADD_CUSTOM_COMMAND( set_source_files_properties(ddl-scan.cpp PROPERTIES COMPILE_FLAGS -Wno-sign-compare) -# Parser puts extra info to stderr. -MY_CHECK_AND_SET_COMPILER_FLAG("-DYYDEBUG=1" DEBUG) - ########### next target ############### ADD_LIBRARY(ddlpackage SHARED diff --git a/dbcon/mysql/CMakeLists.txt b/dbcon/mysql/CMakeLists.txt index c74e19343..0aa6ddcc0 100644 --- a/dbcon/mysql/CMakeLists.txt +++ b/dbcon/mysql/CMakeLists.txt @@ -22,6 +22,8 @@ SET ( libcalmysql_SRCS ha_pseudocolumn.cpp) add_definitions(-DMYSQL_DYNAMIC_PLUGIN) +add_definitions(-DEBUG_WALK_COND) +add_definitions(-DINFINIDB_DEBUG) set_source_files_properties(ha_calpont.cpp PROPERTIES COMPILE_FLAGS "-fno-rtti -fno-implicit-templates") diff --git a/dbcon/mysql/ha_calpont.cpp b/dbcon/mysql/ha_calpont.cpp index 552a895d6..525ac62b7 100644 --- a/dbcon/mysql/ha_calpont.cpp +++ b/dbcon/mysql/ha_calpont.cpp @@ -21,6 +21,7 @@ #define NEED_CALPONT_EXTERNS #include "ha_calpont_impl.h" +#include "ha_mcs_pushdown.h" static handler* calpont_create_handler(handlerton* hton, TABLE_SHARE* table, @@ -31,10 +32,19 @@ static int calpont_commit(handlerton* hton, THD* thd, bool all); static int calpont_rollback(handlerton* hton, THD* thd, bool all); static int calpont_close_connection ( handlerton* hton, THD* thd ); handlerton* calpont_hton; +handlerton* mcs_hton; +// handlers creation function for hton. +// Look into ha_mcs_pushdown.* for more details. static group_by_handler* create_calpont_group_by_handler(THD* thd, Query* query); +static derived_handler* +create_columnstore_derived_handler(THD* thd, TABLE_LIST *derived); + +static select_handler* +create_columnstore_select_handler(THD* thd, SELECT_LEX* sel); + /* Variables for example share methods */ /* @@ -68,6 +78,7 @@ static uchar* calpont_get_key(INFINIDB_SHARE* share, size_t* length, return (uchar*) share->table_name; } +// This one is unused int calpont_discover(handlerton* hton, THD* thd, TABLE_SHARE* share) { DBUG_ENTER("calpont_discover"); @@ -94,6 +105,7 @@ int calpont_discover(handlerton* hton, THD* thd, TABLE_SHARE* share) DBUG_RETURN(my_errno); } +// This f() is also unused int calpont_discover_existence(handlerton* hton, const char* db, const char* table_name) { @@ -107,6 +119,7 @@ static int columnstore_init_func(void* p) struct tm tm; time_t t; + time(&t); localtime_r(&t, &tm); fprintf(stderr, "%02d%02d%02d %2d:%02d:%02d ", @@ -115,22 +128,24 @@ static int columnstore_init_func(void* p) fprintf(stderr, "Columnstore: Started; Version: %s-%s\n", columnstore_version.c_str(), columnstore_release.c_str()); - calpont_hton = (handlerton*)p; + mcs_hton = (handlerton*)p; #ifndef _MSC_VER (void) pthread_mutex_init(&calpont_mutex, MY_MUTEX_INIT_FAST); #endif (void) my_hash_init(&calpont_open_tables, system_charset_info, 32, 0, 0, (my_hash_get_key) calpont_get_key, 0, 0); - calpont_hton->state = SHOW_OPTION_YES; - calpont_hton->create = calpont_create_handler; - calpont_hton->flags = HTON_CAN_RECREATE; -// calpont_hton->discover_table= calpont_discover; -// calpont_hton->discover_table_existence= calpont_discover_existence; - calpont_hton->commit = calpont_commit; - calpont_hton->rollback = calpont_rollback; - calpont_hton->close_connection = calpont_close_connection; - calpont_hton->create_group_by = create_calpont_group_by_handler; + mcs_hton->state = SHOW_OPTION_YES; + mcs_hton->create = calpont_create_handler; + mcs_hton->flags = HTON_CAN_RECREATE; +// mcs_hton->discover_table= calpont_discover; +// mcs_hton->discover_table_existence= calpont_discover_existence; + mcs_hton->commit = calpont_commit; + mcs_hton->rollback = calpont_rollback; + mcs_hton->close_connection = calpont_close_connection; + //mcs_hton->create_group_by = create_calpont_group_by_handler; + mcs_hton->create_derived = create_columnstore_derived_handler; + mcs_hton->create_select = create_columnstore_select_handler; DBUG_RETURN(0); } @@ -159,6 +174,10 @@ static int infinidb_init_func(void* p) calpont_hton->commit = calpont_commit; calpont_hton->rollback = calpont_rollback; calpont_hton->close_connection = calpont_close_connection; + calpont_hton->create_group_by = create_calpont_group_by_handler; + //calpont_hton->create_derived = create_columnstore_derived_handler; + calpont_hton->create_select = create_columnstore_select_handler; + DBUG_RETURN(0); } @@ -264,10 +283,6 @@ int ha_calpont::open(const char* name, int mode, uint32_t test_if_locked) { DBUG_ENTER("ha_calpont::open"); - //if (!(share = get_share(name, table))) - // DBUG_RETURN(1); - //thr_lock_data_init(&share->lock,&lock,NULL); - int rc = ha_calpont_impl_open(name, mode, test_if_locked); DBUG_RETURN(rc); @@ -293,7 +308,6 @@ int ha_calpont::open(const char* name, int mode, uint32_t test_if_locked) int ha_calpont::close(void) { DBUG_ENTER("ha_calpont::close"); - //DBUG_RETURN(free_share(share)); int rc = ha_calpont_impl_close(); @@ -511,7 +525,11 @@ int ha_calpont::rnd_init(bool scan) { DBUG_ENTER("ha_calpont::rnd_init"); - int rc = ha_calpont_impl_rnd_init(table); + int rc = 0; + if(scan) + { + rc = ha_calpont_impl_rnd_init(table); + } DBUG_RETURN(rc); } @@ -929,256 +947,7 @@ struct st_mysql_storage_engine columnstore_storage_engine = struct st_mysql_storage_engine infinidb_storage_engine = { MYSQL_HANDLERTON_INTERFACE_VERSION }; -/*@brief check_walk - It traverses filter conditions*/ -/************************************************************ - * DESCRIPTION: - * It traverses filter predicates looking for unsupported - * JOIN types: non-equi JOIN, e.g t1.c1 > t2.c2; - * logical OR. - * PARAMETERS: - * thd - THD pointer. - * derived - TABLE_LIST* to work with. - * RETURN: - * derived_handler if possible - * NULL in other case - ***********************************************************/ -void check_walk(const Item* item, void* arg) -{ - bool* unsupported_feature = static_cast(arg); - if ( *unsupported_feature ) - return; - switch (item->type()) - { - case Item::FUNC_ITEM: - { - const Item_func* ifp = static_cast(item); - - if ( ifp->functype() != Item_func::EQ_FUNC ) // NON-equi JOIN - { - if ( ifp->argument_count() == 2 && - ifp->arguments()[0]->type() == Item::FIELD_ITEM && - ifp->arguments()[1]->type() == Item::FIELD_ITEM ) - { - Item_field* left= static_cast(ifp->arguments()[0]); - Item_field* right= static_cast(ifp->arguments()[1]); - - if ( left->field->table != right->field->table ) - { - *unsupported_feature = true; - return; - } - } - else // IN + correlated subquery - { - if ( ifp->functype() == Item_func::NOT_FUNC - && ifp->arguments()[0]->type() == Item::EXPR_CACHE_ITEM ) - { - check_walk(ifp->arguments()[0], arg); - } - } - } - break; - } - - case Item::EXPR_CACHE_ITEM: // IN + correlated subquery - { - const Item_cache_wrapper* icw = static_cast(item); - if ( icw->get_orig_item()->type() == Item::FUNC_ITEM ) - { - const Item_func *ifp = static_cast(icw->get_orig_item()); - if ( ifp->argument_count() == 2 && - ( ifp->arguments()[0]->type() == Item::Item::SUBSELECT_ITEM - || ifp->arguments()[1]->type() == Item::Item::SUBSELECT_ITEM )) - { - *unsupported_feature = true; - return; - } - } - break; - } - - case Item::COND_ITEM: // OR in cods is unsupported yet - { - Item_cond* icp = (Item_cond*)item; - if ( is_cond_or(icp) ) - { - *unsupported_feature = true; - } - break; - } - default: - { - break; - } - } -} - -/*@brief create_calpont_group_by_handler- Creates handler*/ -/*********************************************************** - * DESCRIPTION: - * Creates a group_by pushdown handler if there is no: - * non-equi JOIN, e.g * t1.c1 > t2.c2 - * logical OR in the filter predicates - * Impossible WHERE - * Impossible HAVING - * and there is either GROUP BY or aggregation function - * exists at the top level. - * Valid queries with the last two crashes the server if - * processed. - * Details are in server/sql/group_by_handler.h - * PARAMETERS: - * thd - THD pointer - * query - Query structure LFM in group_by_handler.h - * RETURN: - * group_by_handler if success - * NULL in other case - ***********************************************************/ -static group_by_handler* -create_calpont_group_by_handler(THD* thd, Query* query) -{ - ha_calpont_group_by_handler* handler = NULL; - // same as thd->lex->current_select - SELECT_LEX *select_lex = query->from->select_lex; - - // Create a handler if query is valid. See comments for details. - if ( thd->infinidb_vtable.vtable_state == THD::INFINIDB_DISABLE_VTABLE - && ( thd->variables.infinidb_vtable_mode == 0 - || thd->variables.infinidb_vtable_mode == 2 ) - && ( query->group_by || select_lex->with_sum_func ) ) - { - bool unsupported_feature = false; - // revisit SELECT_LEX for all units - for(TABLE_LIST* tl = query->from; !unsupported_feature && tl; tl = tl->next_global) - { - select_lex = tl->select_lex; - // Correlation subquery. Comming soon so fail on this yet. - unsupported_feature = select_lex->is_correlated; - - // Impossible HAVING or WHERE - if ( ( !unsupported_feature && query->having && select_lex->having_value == Item::COND_FALSE ) - || ( select_lex->cond_count > 0 - && select_lex->cond_value == Item::COND_FALSE ) ) - { - unsupported_feature = true; - } - - // Unsupported JOIN conditions - if ( !unsupported_feature ) - { - JOIN *join = select_lex->join; - Item_cond *icp = 0; - - if (join != 0) - icp = reinterpret_cast(join->conds); - - if ( unsupported_feature == false - && icp ) - { - icp->traverse_cond(check_walk, &unsupported_feature, Item::POSTFIX); - } - - // Optimizer could move some join conditions into where - if (select_lex->where != 0) - icp = reinterpret_cast(select_lex->where); - - if ( unsupported_feature == false - && icp ) - { - icp->traverse_cond(check_walk, &unsupported_feature, Item::POSTFIX); - } - - } - } // unsupported features check ends here - - if ( !unsupported_feature ) - { - handler = new ha_calpont_group_by_handler(thd, query); - - // Notify the server, that CS handles GROUP BY, ORDER BY and HAVING clauses. - query->group_by = NULL; - query->order_by = NULL; - query->having = NULL; - } - } - - return handler; -} - -/*********************************************************** - * DESCRIPTION: - * GROUP BY handler constructor - * PARAMETERS: - * thd - THD pointer. - * query - Query describing structure - ***********************************************************/ -ha_calpont_group_by_handler::ha_calpont_group_by_handler(THD* thd_arg, Query* query) - : group_by_handler(thd_arg, calpont_hton), - select(query->select), - table_list(query->from), - distinct(query->distinct), - where(query->where), - group_by(query->group_by), - order_by(query->order_by), - having(query->having) -{ -} - -/*********************************************************** - * DESCRIPTION: - * GROUP BY destructor - ***********************************************************/ -ha_calpont_group_by_handler::~ha_calpont_group_by_handler() -{ -} - -/*********************************************************** - * DESCRIPTION: - * Makes the plan and prepares the data - * RETURN: - * int rc - ***********************************************************/ -int ha_calpont_group_by_handler::init_scan() -{ - DBUG_ENTER("ha_calpont_group_by_handler::init_scan"); - - // Save vtable_state to restore the after we inited. - THD::infinidb_state oldState = thd->infinidb_vtable.vtable_state; - // MCOL-1052 Should be removed after cleaning the code up. - thd->infinidb_vtable.vtable_state = THD::INFINIDB_CREATE_VTABLE; - int rc = ha_calpont_impl_group_by_init(this, table); - thd->infinidb_vtable.vtable_state = oldState; - - DBUG_RETURN(rc); -} - -/*********************************************************** - * DESCRIPTION: - * Fetches a row and saves it to a temporary table. - * RETURN: - * int rc - ***********************************************************/ -int ha_calpont_group_by_handler::next_row() -{ - DBUG_ENTER("ha_calpont_group_by_handler::next_row"); - int rc = ha_calpont_impl_group_by_next(this, table); - - DBUG_RETURN(rc); -} - -/*********************************************************** - * DESCRIPTION: - * Shuts the scan down. - * RETURN: - * int rc - ***********************************************************/ -int ha_calpont_group_by_handler::end_scan() -{ - DBUG_ENTER("ha_calpont_group_by_handler::end_scan"); - - int rc = ha_calpont_impl_group_by_end(this, table); - - DBUG_RETURN(rc); -} +#include "ha_mcs_pushdown.cpp" mysql_declare_plugin(columnstore) { diff --git a/dbcon/mysql/ha_calpont.h b/dbcon/mysql/ha_calpont.h index bab756851..3d184f955 100644 --- a/dbcon/mysql/ha_calpont.h +++ b/dbcon/mysql/ha_calpont.h @@ -22,9 +22,10 @@ #include "ha_mcs_sysvars.h" extern handlerton* calpont_hton; +extern handlerton* mcs_hton; /** @brief - This structure will be shared among all open handlers. + INFINIDB_SHARE is a structure that will be shared among all open handlers. This example implements the minimum of what you will probably need. */ typedef struct st_calpont_share @@ -228,51 +229,4 @@ public: } }; - -/*@brief group_by_handler class*/ -/*********************************************************** - * DESCRIPTION: - * Provides server with group_by_handler API methods. - * One should read comments in server/sql/group_by_handler.h - * Attributes: - * select - attribute contains all GROUP BY, HAVING, ORDER items and calls it - * an extended SELECT list according to comments in - * server/sql/group_handler.cc. - * So the temporary table for - * select count(*) from b group by a having a > 3 order by a - * will have 4 columns not 1. - * However server ignores all NULLs used in - * GROUP BY, HAVING, ORDER. - * select_list_descr - contains Item description returned by Item->print() - * that is used in lookup for corresponding columns in - * extended SELECT list. - * table_list - contains all tables involved. Must be CS tables only. - * distinct - looks like a useless thing for now. Couldn't get it set by server. - * where - where items. - * group_by - group by ORDER items. - * order_by - order by ORDER items. - * having - having Item. - * Methods: - * init_scan - get plan and send it to ExeMgr. Get the execution result. - * next_row - get a row back from sm. - * end_scan - finish and clean the things up. - ***********************************************************/ -class ha_calpont_group_by_handler: public group_by_handler -{ -public: - ha_calpont_group_by_handler(THD* thd_arg, Query* query); - ~ha_calpont_group_by_handler(); - int init_scan(); - int next_row(); - int end_scan(); - - List* select; - TABLE_LIST* table_list; - bool distinct; - Item* where; - ORDER* group_by; - ORDER* order_by; - Item* having; -}; #endif //HA_CALPONT_H__ - diff --git a/dbcon/mysql/ha_calpont_ddl.cpp b/dbcon/mysql/ha_calpont_ddl.cpp index 833a0ab38..05fb71203 100644 --- a/dbcon/mysql/ha_calpont_ddl.cpp +++ b/dbcon/mysql/ha_calpont_ddl.cpp @@ -2306,17 +2306,6 @@ int ha_calpont_impl_create_(const char* name, TABLE* table_arg, HA_CREATE_INFO* bool schemaSyncOnly = false; bool isCreate = true; - // relate to bug 1793. Make sure this is not for a select statement because - if (db == "calpontsys" && thd->infinidb_vtable.vtable_state == THD::INFINIDB_INIT - && tbl != "systable" - && tbl != "syscolumn" && tbl != "sysindex" - && tbl != "sysconstraint" && tbl != "sysindexcol" - && tbl != "sysconstraintcol" ) - { - setError(thd, ER_INTERNAL_ERROR, "Cannot create non-system Calpont tables in calpontsys database"); - return 1; - } - regex pat("[[:space:]]*SCHEMA[[:space:]]+SYNC[[:space:]]+ONLY", regex_constants::extended); if (regex_search(tablecomment, pat)) @@ -2336,11 +2325,6 @@ int ha_calpont_impl_create_(const char* name, TABLE* table_arg, HA_CREATE_INFO* #endif return 0; } - - if (thd->infinidb_vtable.vtable_state == THD::INFINIDB_ALTER_VTABLE) //check if it is select - { - return 0; - } } else { diff --git a/dbcon/mysql/ha_calpont_dml.cpp b/dbcon/mysql/ha_calpont_dml.cpp index a428a2ca5..745771dfb 100644 --- a/dbcon/mysql/ha_calpont_dml.cpp +++ b/dbcon/mysql/ha_calpont_dml.cpp @@ -2110,10 +2110,6 @@ int ha_calpont_impl_commit_ (handlerton* hton, THD* thd, bool all, cal_connectio { int rc = 0; - if (thd->infinidb_vtable.vtable_state == THD::INFINIDB_ALTER_VTABLE || - thd->infinidb_vtable.vtable_state == THD::INFINIDB_SELECT_VTABLE ) - return rc; - if (thd->slave_thread && !ci.replicationEnabled) return 0; diff --git a/dbcon/mysql/ha_calpont_execplan.cpp b/dbcon/mysql/ha_calpont_execplan.cpp index c36f9315d..cbeaf2e8f 100644 --- a/dbcon/mysql/ha_calpont_execplan.cpp +++ b/dbcon/mysql/ha_calpont_execplan.cpp @@ -19,7 +19,7 @@ /* * $Id: ha_calpont_execplan.cpp 9749 2013-08-15 04:00:39Z zzhu $ */ - + /** @file */ //#define DEBUG_WALK_COND #include @@ -192,6 +192,154 @@ bool nonConstFunc(Item_func* ifp) return false; } +/*@brief getColNameFromItem - builds a name from an Item */ +/*********************************************************** + * DESCRIPTION: + * This f() looks for a first proper Item_ident and populate + * ostream with schema, table and column names. + * Used to build db.table.field tuple for debugging output + * in getSelectPlan(). TBD getGroupPlan must use this also. + * PARAMETERS: + * item source Item* + * ostream output stream + * RETURNS + * void + ***********************************************************/ +void getColNameFromItem(std::ostringstream& ostream, Item* item) +{ +// MCOL-2121 WIP +// Item_func doesn't have proper db.table.field values +// inherited from Item_ident. TBD what is the valid output. +// !!!dynamic_cast fails compilation + ostream << "'"; + + if (item->type() != Item::FIELD_ITEM) + { + ostream << "unknown db" << '.'; + ostream << "unknown table" << '.'; + ostream << "unknown field"; + } + else + { + Item_ident* iip = reinterpret_cast(item); + + if (iip->db_name) + ostream << iip->db_name << '.'; + else + ostream << "unknown db" << '.'; + + if (iip->table_name) + ostream << iip->table_name << '.'; + else + ostream << "unknown table" << '.'; + + if (iip->field_name.length) + ostream << iip->field_name.str; + else + ostream << "unknown field"; + } + + ostream << "'"; + return; +} + +/*@brf sortItemIsInGroupRec - seeks for an item in grouping*/ +/*********************************************************** + * DESCRIPTION: + * This f() recursively traverses grouping items and looks + * for an FUNC_ITEM, REF_ITEM or FIELD_ITEM. + * f() is used by sortItemIsInGrouping(). + * PARAMETERS: + * sort_item Item* used to build aggregation. + * group_item GROUP BY item. + * RETURNS + * bool + ***********************************************************/ +bool sortItemIsInGroupRec(Item* sort_item, Item* group_item) +{ + bool found = false; + // If ITEM_REF::ref is NULL + if (sort_item == NULL) + { + return found; + } + + Item_func* ifp_sort = reinterpret_cast(sort_item); + + // base cases for Item_field and Item_ref. The second arg is binary cmp switch + found = group_item->eq(sort_item, false); + if (!found && sort_item->type() == Item::REF_ITEM) + { + Item_ref* ifp_sort_ref = reinterpret_cast(sort_item); + found = sortItemIsInGroupRec(*ifp_sort_ref->ref, group_item); + } + else if (!found && sort_item->type() == Item::FIELD_ITEM) + { + return found; + } + + // seeking for a group_item match + for (uint32_t i = 0; !found && i < ifp_sort->argument_count(); i++) + { + Item* ifp_sort_arg = ifp_sort->arguments()[i]; + if (ifp_sort_arg->type() == Item::FUNC_ITEM + || ifp_sort_arg->type() == Item::FIELD_ITEM) + { + Item* ifp_sort_arg = ifp_sort->arguments()[i]; + found = sortItemIsInGroupRec(ifp_sort_arg, group_item); + } + else if (ifp_sort_arg->type() == Item::REF_ITEM) + { + // dereference the Item + Item_ref* ifp_sort_ref = reinterpret_cast(ifp_sort_arg); + found = sortItemIsInGroupRec(*ifp_sort_ref->ref, group_item); + } + } + + return found; +} + +/*@brief sortItemIsInGrouping- seeks for an item in grouping*/ +/*********************************************************** + * DESCRIPTION: + * This f() traverses grouping items and looks for an item. + * only Item_fields, Item_func are considered. However there + * could be Item_ref down the tree. + * f() is used in sorting parsing by getSelectPlan(). + * PARAMETERS: + * sort_item Item* used to build aggregation. + * groupcol GROUP BY items from this unit. + * RETURNS + * bool + ***********************************************************/ +bool sortItemIsInGrouping(Item* sort_item, ORDER* groupcol) +{ + bool found = false; + + if(sort_item->type() == Item::SUM_FUNC_ITEM) + { + found = true; + } + + for (; !found && groupcol; groupcol = groupcol->next) + { + Item* group_item = *(groupcol->item); + found = (group_item->eq(sort_item, false)) ? true : false; + // Detect aggregation functions first then traverse + // if sort field is a Func and group field + // is either Field or Func + // Consider nonConstFunc() check here + if(!found && sort_item->type() == Item::FUNC_ITEM + && (group_item->type() == Item::FUNC_ITEM + || group_item->type() == Item::FIELD_ITEM)) + { + found = sortItemIsInGroupRec(sort_item, group_item); + } + } + + return found; +} + /*@brief buildAggFrmTempField- build aggr func from extSELECT list item*/ /*********************************************************** * DESCRIPTION: @@ -230,7 +378,6 @@ ReturnedColumn* buildAggFrmTempField(Item* item, gp_walk_info& gwi) std::vector::iterator iter = gwi.extSelAggColsItems.begin(); for ( ; iter != gwi.extSelAggColsItems.end(); iter++ ) { - //Item* temp_isfp = *iter; isfp = reinterpret_cast(*iter); if ( isfp->type() == Item::SUM_FUNC_ITEM && @@ -286,40 +433,61 @@ void debug_walk(const Item* item, void* arg) '.' << ifp->field_name.str << endl; break; } - - case Item::INT_ITEM: + case Item::CONST_ITEM: { - Item_int* iip = (Item_int*)item; - cerr << "INT_ITEM: "; + switch (item->cmp_type()) + { + case INT_RESULT: + { + Item_int* iip = (Item_int*)item; + cerr << "INT_ITEM: "; - if (iip->name.length) cerr << iip->name.str << " (from name string)" << endl; - else cerr << iip->val_int() << endl; + if (iip->name.length) cerr << iip->name.str << " (from name string)" << endl; + else cerr << iip->val_int() << endl; + break; + } + case STRING_RESULT: + { + Item_string* isp = (Item_string*)item; + String val, *str = isp->val_str(&val); + string valStr; + valStr.assign(str->ptr(), str->length()); + cerr << "STRING_ITEM: >" << valStr << '<' << endl; + break; + } + case REAL_RESULT: + { + cerr << "REAL_ITEM" << endl; + break; + } + case DECIMAL_RESULT: + { + cerr << "DECIMAL_ITEM" << endl; + break; + } + case TIME_RESULT: + { + String val, *str = NULL; + Item_temporal_literal* itp = (Item_temporal_literal*)item; + str = itp->val_str(&val); + cerr << "DATE ITEM: "; + + if (str) + cerr << ": (" << str->ptr() << ')' << endl; + else + cerr << ": " << endl; + + break; + } + default: + { + cerr << ": Unknown cmp_type" << endl; + break; + } + } break; } - - case Item::STRING_ITEM: - { - Item_string* isp = (Item_string*)item; - String val, *str = isp->val_str(&val); - string valStr; - valStr.assign(str->ptr(), str->length()); - cerr << "STRING_ITEM: >" << valStr << '<' << endl; - break; - } - - case Item::REAL_ITEM: - { - cerr << "REAL_ITEM" << endl; - break; - } - - case Item::DECIMAL_ITEM: - { - cerr << "DECIMAL_ITEM" << endl; - break; - } - case Item::FUNC_ITEM: { Item_func* ifp = (Item_func*)item; @@ -570,7 +738,8 @@ void debug_walk(const Item* item, void* arg) item_name = const_cast(isp->get_arg(0)->name.str); } else if (!item_name && isp->get_arg_count() - && isp->get_arg(0)->type() == Item::INT_ITEM) + && isp->get_arg(0)->type() == Item::CONST_ITEM + && isp->get_arg(0)->cmp_type() == INT_RESULT) { item_name = (char*)"INT||*"; } @@ -961,21 +1130,6 @@ void debug_walk(const Item* item, void* arg) break; } - case Item::DATE_ITEM: - { - String val, *str = NULL; - Item_temporal_literal* itp = (Item_temporal_literal*)item; - str = itp->val_str(&val); - cerr << "DATE ITEM: "; - - if (str) - cerr << ": (" << str->ptr() << ')' << endl; - else - cerr << ": " << endl; - - break; - } - case Item::WINDOW_FUNC_ITEM: { Item_window_func* ifp = (Item_window_func*)item; @@ -989,6 +1143,12 @@ void debug_walk(const Item* item, void* arg) break; } + case Item::TYPE_HOLDER: + { + cerr << "TYPE_HOLDER item with cmp_type " << item->cmp_type() << endl; + break; + } + default: { cerr << "UNKNOWN_ITEM type " << item->type() << endl; @@ -1161,8 +1321,9 @@ uint32_t buildOuterJoin(gp_walk_info& gwi, SELECT_LEX& select_lex) { if (gwi.thd->derived_tables_processing) { - gwi.thd->infinidb_vtable.isUnion = false; - gwi.thd->infinidb_vtable.isUpdateWithDerive = true; +// TODO MCOL-2178 isUnion member only assigned, never used +// MIGR::infinidb_vtable.isUnion = false; + gwi.cs_vtable_is_update_with_derive = true; return -1; } } @@ -1441,7 +1602,7 @@ bool buildPredicateItem(Item_func* ifp, gp_walk_info* gwip) { // Starting with MariaDB 10.2, LIKE uses a negated flag instead of FUNC_NOT // Further processing is done below as before for LIKE - if (((Item_func_like*)ifp)->negated) + if (((Item_func_like*)ifp)->get_negated()) { sop->reverseOp(); } @@ -1579,7 +1740,7 @@ bool buildPredicateItem(Item_func* ifp, gp_walk_info* gwip) String str; // @bug5811. This filter string is for cross engine to use. // Use real table name. - ifp->print(&str, QT_INFINIDB_DERIVED); + ifp->print(&str, QT_ORDINARY); IDEBUG(cerr << str.ptr() << endl); if (str.ptr()) @@ -2492,8 +2653,6 @@ void setError(THD* thd, uint32_t errcode, string errmsg) } thd->raise_error_printf(errcode, errmsg.c_str()); - thd->infinidb_vtable.isNewQuery = true; - thd->infinidb_vtable.override_largeside_estimate = false; // reset expressionID if (get_fe_conn_info_ptr() == NULL) @@ -2607,7 +2766,7 @@ uint32_t setAggOp(AggregateColumn* ac, Item_sum* isp) { Item_func_group_concat* gc = (Item_func_group_concat*)isp; ac->aggOp(AggregateColumn::GROUP_CONCAT); - ac->distinct(gc->isDistinct()); + ac->distinct(gc->get_distinct()); return rc; } @@ -2885,7 +3044,7 @@ ReturnedColumn* buildReturnedColumn(Item* item, gp_walk_info& gwi, bool& nonSupp { //if ( ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE ) || ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE_MULTI )) { - if ( !item->fixed) + if ( !item->is_fixed()) { item->fix_fields(gwi.thd, (Item**)&item); } @@ -2899,59 +3058,71 @@ ReturnedColumn* buildReturnedColumn(Item* item, gp_walk_info& gwi, bool& nonSupp Item_field* ifp = (Item_field*)item; return buildSimpleColumn(ifp, gwi); } - - case Item::INT_ITEM: - case Item::VARBIN_ITEM: + case Item::CONST_ITEM: { - String val, *str = item->val_str(&val); - string valStr; - valStr.assign(str->ptr(), str->length()); - - if (item->unsigned_flag) + switch (item->cmp_type()) { - //cc = new ConstantColumn(valStr, (uint64_t)item->val_uint(), ConstantColumn::NUM); - // It seems that str at this point is crap if val_uint() is > MAX_BIGINT. By using - // this constructor, ConstantColumn is built with the proper string. For whatever reason, - // ExeMgr converts the fConstval member to numeric, rather than using the existing numeric - // values available, so it's important to have fConstval correct. - rc = new ConstantColumn((uint64_t)item->val_uint(), ConstantColumn::NUM); + case INT_RESULT: + { + String val, *str = item->val_str(&val); + string valStr; + valStr.assign(str->ptr(), str->length()); + + if (item->unsigned_flag) + { + rc = new ConstantColumn((uint64_t)item->val_uint(), ConstantColumn::NUM); + } + else + { + rc = new ConstantColumn(valStr, (int64_t)item->val_int(), ConstantColumn::NUM); + } + + break; + } + case STRING_RESULT: + { + String val, *str = item->val_str(&val); + string valStr; + valStr.assign(str->ptr(), str->length()); + rc = new ConstantColumn(valStr); + break; + } + case REAL_RESULT: + { + String val, *str = item->val_str(&val); + string valStr; + valStr.assign(str->ptr(), str->length()); + rc = new ConstantColumn(valStr, item->val_real()); + break; + } + case DECIMAL_RESULT: + { + rc = buildDecimalColumn(item, gwi); + break; + } + case TIME_RESULT: + { + String val, *str = item->val_str(&val); + string valStr; + valStr.assign(str->ptr(), str->length()); + rc = new ConstantColumn(valStr); + break; + } + default: + { + gwi.fatalParseError = true; + gwi.parseErrorText = "Unknown item type"; + break; + } } - else + + if (rc && (item->cmp_type() != DECIMAL_RESULT)) { - rc = new ConstantColumn(valStr, (int64_t)item->val_int(), ConstantColumn::NUM); + (dynamic_cast(rc))->timeZone(gwi.thd->variables.time_zone->get_name()->ptr()); } - (dynamic_cast(rc))->timeZone(gwi.thd->variables.time_zone->get_name()->ptr()); - //return cc; break; } - - case Item::STRING_ITEM: - { - String val, *str = item->val_str(&val); - string valStr; - valStr.assign(str->ptr(), str->length()); - rc = new ConstantColumn(valStr); - (dynamic_cast(rc))->timeZone(gwi.thd->variables.time_zone->get_name()->ptr()); - break; - } - - case Item::REAL_ITEM: - { - String val, *str = item->val_str(&val); - string valStr; - valStr.assign(str->ptr(), str->length()); - rc = new ConstantColumn(valStr, item->val_real()); - (dynamic_cast(rc))->timeZone(gwi.thd->variables.time_zone->get_name()->ptr()); - break; - } - - case Item::DECIMAL_ITEM: - { - rc = buildDecimalColumn(item, gwi); - break; - } - case Item::FUNC_ITEM: { Item_func* ifp = (Item_func*)item; @@ -2961,7 +3132,7 @@ ReturnedColumn* buildReturnedColumn(Item* item, gp_walk_info& gwi, bool& nonSupp vector tmpVec; //bool hasAggColumn = false; uint16_t parseInfo = 0; - parse_item(ifp, tmpVec, gwi.fatalParseError, parseInfo); + parse_item(ifp, tmpVec, gwi.fatalParseError, parseInfo, &gwi); if (parseInfo & SUB_BIT) { @@ -3085,16 +3256,6 @@ ReturnedColumn* buildReturnedColumn(Item* item, gp_walk_info& gwi, bool& nonSupp break; } - case Item::DATE_ITEM: - { - String val, *str = item->val_str(&val); - string valStr; - valStr.assign(str->ptr(), str->length()); - rc = new ConstantColumn(valStr); - (dynamic_cast(rc))->timeZone(gwi.thd->variables.time_zone->get_name()->ptr()); - break; - } - case Item::WINDOW_FUNC_ITEM: { return buildWindowFunctionColumn(item, gwi, nonSupport); @@ -3451,18 +3612,23 @@ ReturnedColumn* buildFunctionColumn( for (uint32_t i = 1; i < ifp->argument_count(); i++) { - if (!(ifp->arguments()[i]->type() == Item::INT_ITEM || - ifp->arguments()[i]->type() == Item::STRING_ITEM || - ifp->arguments()[i]->type() == Item::REAL_ITEM || - ifp->arguments()[i]->type() == Item::DECIMAL_ITEM || - ifp->arguments()[i]->type() == Item::NULL_ITEM)) + if (!(ifp->arguments()[i]->type() == Item::NULL_ITEM || + (ifp->arguments()[i]->type() == Item::CONST_ITEM && + (ifp->arguments()[i]->cmp_type() == INT_RESULT || + ifp->arguments()[i]->cmp_type() == STRING_RESULT || + ifp->arguments()[i]->cmp_type() == REAL_RESULT || + ifp->arguments()[i]->cmp_type() == DECIMAL_RESULT + ) + ) + ) + ) { if (ifp->arguments()[i]->type() == Item::FUNC_ITEM) { // try to identify const F&E. fall to primitive if parms are constant F&E. vector tmpVec; uint16_t parseInfo = 0; - parse_item(ifp->arguments()[i], tmpVec, gwi.fatalParseError, parseInfo); + parse_item(ifp->arguments()[i], tmpVec, gwi.fatalParseError, parseInfo, &gwi); if (!gwi.fatalParseError && !(parseInfo & AF_BIT) && tmpVec.size() == 0) continue; @@ -4086,10 +4252,10 @@ SimpleColumn* buildSimpleColumn(Item_field* ifp, gp_walk_info& gwi) { // check foreign engine if (ifp->cached_table && ifp->cached_table->table) - infiniDB = isInfiniDB(ifp->cached_table->table); + infiniDB = isMCSTable(ifp->cached_table->table); // @bug4509. ifp->cached_table could be null for myisam sometimes else if (ifp->field && ifp->field->table) - infiniDB = isInfiniDB(ifp->field->table); + infiniDB = isMCSTable(ifp->field->table); if (infiniDB) { @@ -4328,7 +4494,7 @@ ReturnedColumn* buildAggregateColumn(Item* item, gp_walk_info& gwi) RowColumn* rowCol = new RowColumn(); vector selCols; - uint32_t select_ctn = gc->count_field(); + uint32_t select_ctn = gc->get_count_field(); ReturnedColumn* rc = NULL; for (uint32_t i = 0; i < select_ctn; i++) @@ -4349,12 +4515,13 @@ ReturnedColumn* buildAggregateColumn(Item* item, gp_walk_info& gwi) ORDER** order_item, **end; for (order_item = gc->get_order(), - end = order_item + gc->order_field(); order_item < end; + end = order_item + gc->get_order_field(); order_item < end; order_item++) { Item* ord_col = *(*order_item)->item; - if (ord_col->type() == Item::INT_ITEM) + if (ord_col->type() == Item::CONST_ITEM + && ord_col->cmp_type() == INT_RESULT) { Item_int* id = (Item_int*)ord_col; @@ -4394,10 +4561,10 @@ ReturnedColumn* buildAggregateColumn(Item* item, gp_walk_info& gwi) parm.reset(rowCol); ac->aggParms().push_back(parm); - if (gc->str_separator()) + if (gc->get_separator()) { string separator; - separator.assign(gc->str_separator()->ptr(), gc->str_separator()->length()); + separator.assign(gc->get_separator()->ptr(), gc->get_separator()->length()); (dynamic_cast(ac))->separator(separator); } } @@ -4428,18 +4595,29 @@ ReturnedColumn* buildAggregateColumn(Item* item, gp_walk_info& gwi) break; } - case Item::INT_ITEM: - case Item::STRING_ITEM: - case Item::REAL_ITEM: - case Item::DECIMAL_ITEM: + case Item::CONST_ITEM: { - // treat as count(*) - if (ac->aggOp() == AggregateColumn::COUNT) - ac->aggOp(AggregateColumn::COUNT_ASTERISK); + switch(sfitemp->cmp_type()) + { + case INT_RESULT: + case STRING_RESULT: + case REAL_RESULT: + case DECIMAL_RESULT: + { + // treat as count(*) + if (ac->aggOp() == AggregateColumn::COUNT) + ac->aggOp(AggregateColumn::COUNT_ASTERISK); - parm.reset(buildReturnedColumn(sfitemp, gwi, gwi.fatalParseError)); - ac->constCol(parm); - bIsConst = true; + parm.reset(buildReturnedColumn(sfitemp, gwi, gwi.fatalParseError)); + ac->constCol(parm); + bIsConst = true; + break; + } + default: + { + gwi.fatalParseError = true; + } + } break; } @@ -4459,7 +4637,7 @@ ReturnedColumn* buildAggregateColumn(Item* item, gp_walk_info& gwi) // check count(1+1) case vector tmpVec; uint16_t parseInfo = 0; - parse_item(ifp, tmpVec, gwi.fatalParseError, parseInfo); + parse_item(ifp, tmpVec, gwi.fatalParseError, parseInfo, &gwi); if (parseInfo & SUB_BIT) { @@ -4523,7 +4701,6 @@ ReturnedColumn* buildAggregateColumn(Item* item, gp_walk_info& gwi) default: { gwi.fatalParseError = true; - //gwi.parseErrorText = "Non-supported Item in Aggregate function"; } } @@ -4786,7 +4963,7 @@ void addIntervalArgs(THD* thd, Item_func* ifp, FunctionParm& functionParms) if (funcName == "date_add_interval") interval_type = ((Item_date_add_interval*)ifp)->int_type; else if (funcName == "timestampdiff") - interval_type = ((Item_func_timestamp_diff*)ifp)->int_type; + interval_type = ((Item_func_timestamp_diff*)ifp)->get_int_type(); else if (funcName == "extract") interval_type = ((Item_extract*)ifp)->int_type; @@ -4823,7 +5000,7 @@ void castCharArgs(THD* thd, Item_func* ifp, FunctionParm& functionParms) Item_char_typecast* idai = (Item_char_typecast*)ifp; SPTP sptp; - sptp.reset(new ParseTree(new ConstantColumn((int64_t)idai->castLength()))); + sptp.reset(new ParseTree(new ConstantColumn((int64_t)idai->get_cast_length()))); (dynamic_cast(sptp->data()))->timeZone(thd->variables.time_zone->get_name()->ptr()); functionParms.push_back(sptp); } @@ -4922,67 +5099,96 @@ void gp_walk(const Item* item, void* arg) break; } - case Item::INT_ITEM: + case Item::CONST_ITEM: { - Item_int* iip = (Item_int*)item; - gwip->rcWorkStack.push(buildReturnedColumn(iip, *gwip, gwip->fatalParseError)); - break; - } - - case Item::STRING_ITEM: - { - Item_string* isp = (Item_string*)item; - - if (isp) + switch(item->cmp_type()) { - if (isp->result_type() == STRING_RESULT) + case INT_RESULT: { - String val, *str = isp->val_str(&val); - string cval; - - if (str->ptr()) - { - cval.assign(str->ptr(), str->length()); - } - - gwip->rcWorkStack.push(new ConstantColumn(cval)); - (dynamic_cast(gwip->rcWorkStack.top()))->timeZone(gwip->thd->variables.time_zone->get_name()->ptr()); + Item_int* iip = (Item_int*)item; + gwip->rcWorkStack.push(buildReturnedColumn(iip, *gwip, gwip->fatalParseError)); break; } - gwip->rcWorkStack.push(buildReturnedColumn(isp, *gwip, gwip->fatalParseError)); + case STRING_RESULT: + { + Item_string* isp = (Item_string*)item; + + if (isp) + { + if (isp->result_type() == STRING_RESULT) + { + String val, *str = isp->val_str(&val); + string cval; + + if (str->ptr()) + { + cval.assign(str->ptr(), str->length()); + } + + gwip->rcWorkStack.push(new ConstantColumn(cval)); + (dynamic_cast(gwip->rcWorkStack.top()))->timeZone(gwip->thd->variables.time_zone->get_name()->ptr()); + break; + } + + gwip->rcWorkStack.push(buildReturnedColumn(isp, *gwip, gwip->fatalParseError)); + } + break; + } + + case REAL_RESULT: + { + Item_float* ifp = (Item_float*)item; + gwip->rcWorkStack.push(buildReturnedColumn(ifp, *gwip, gwip->fatalParseError)); + break; + } + + case DECIMAL_RESULT: + { + Item_decimal* idp = (Item_decimal*)item; + gwip->rcWorkStack.push(buildReturnedColumn(idp, *gwip, gwip->fatalParseError)); + break; + } + + case TIME_RESULT: + { + Item_temporal_literal* itp = (Item_temporal_literal*)item; + gwip->rcWorkStack.push(buildReturnedColumn(itp, *gwip, gwip->fatalParseError)); + break; + } + /*case Item::VARBIN_ITEM: + { + Item_hex_string* hdp = (Item_hex_string*)item; + gwip->rcWorkStack.push(buildReturnedColumn(hdp, *gwip, gwip->fatalParseError)); + break; + }*/ + default: + { + if (gwip->condPush) + { + // push noop for unhandled item + SimpleColumn* rc = new SimpleColumn("noop"); + rc->timeZone(gwip->thd->variables.time_zone->get_name()->ptr()); + gwip->rcWorkStack.push(rc); + break; + } + + ostringstream oss; + oss << "Unhandled Item type: " << item->type(); + gwip->parseErrorText = oss.str(); + gwip->fatalParseError = true; + break; + } } - break; } - - case Item::REAL_ITEM: - { - Item_float* ifp = (Item_float*)item; - gwip->rcWorkStack.push(buildReturnedColumn(ifp, *gwip, gwip->fatalParseError)); - break; - } - - case Item::DECIMAL_ITEM: - { - Item_decimal* idp = (Item_decimal*)item; - gwip->rcWorkStack.push(buildReturnedColumn(idp, *gwip, gwip->fatalParseError)); - break; - } - - case Item::VARBIN_ITEM: - { - Item_hex_string* hdp = (Item_hex_string*)item; - gwip->rcWorkStack.push(buildReturnedColumn(hdp, *gwip, gwip->fatalParseError)); - break; - } - case Item::NULL_ITEM: { if (gwip->condPush) { // push noop for unhandled item SimpleColumn* rc = new SimpleColumn("noop"); + rc->timeZone(gwip->thd->variables.time_zone->get_name()->ptr()); gwip->rcWorkStack.push(rc); break; } @@ -5044,7 +5250,7 @@ void gp_walk(const Item* item, void* arg) // try to evaluate const F&E vector tmpVec; uint16_t parseInfo = 0; - parse_item(ifp, tmpVec, gwip->fatalParseError, parseInfo); + parse_item(ifp, tmpVec, gwip->fatalParseError, parseInfo, gwip); // table mode takes only one table filter if (gwip->condPush) @@ -5209,7 +5415,7 @@ void gp_walk(const Item* item, void* arg) { vector fieldVec; uint16_t parseInfo = 0; - parse_item(it, fieldVec, gwip->fatalParseError, parseInfo); + parse_item(it, fieldVec, gwip->fatalParseError, parseInfo, gwip); if (parseInfo & CORRELATED) { @@ -5220,10 +5426,13 @@ void gp_walk(const Item* item, void* arg) } if ((it->type() == Item::FIELD_ITEM - || it->type() == Item::INT_ITEM - || it->type() == Item::DECIMAL_ITEM - || it->type() == Item::STRING_ITEM - || it->type() == Item::REAL_ITEM + || ( it->type() == Item::CONST_ITEM + && ( it->cmp_type() == INT_RESULT + || it->cmp_type() == DECIMAL_RESULT + || it->cmp_type() == STRING_RESULT + || it->cmp_type() == REAL_RESULT + ) + ) || it->type() == Item::NULL_ITEM || (it->type() == Item::FUNC_ITEM && !isPredicateFunction(it, gwip))) && !gwip->rcWorkStack.empty() @@ -5420,14 +5629,15 @@ void gp_walk(const Item* item, void* arg) gwip->hasSubSelect = true; gwip->subQuery = existsSub; gwip->ptWorkStack.push(existsSub->transform()); - current_thd->infinidb_vtable.isUnion = true; // only temp. bypass the 2nd phase. +// TODO MCOL-2178 isUnion member only assigned, never used +// MIGR::infinidb_vtable.isUnion = true; // only temp. bypass the 2nd phase. // recover original gwip->subQuery = orig; gwip->lastSub = existsSub; } else if (sub->substype() == Item_subselect::IN_SUBS) { - if (!((Item_in_subselect*)sub)->getOptimizer() && gwip->thd->derived_tables_processing) + if (!((Item_in_subselect*)sub)->optimizer && gwip->thd->derived_tables_processing) { ostringstream oss; oss << "Invalid In_optimizer: " << item->type(); @@ -5466,12 +5676,6 @@ void gp_walk(const Item* item, void* arg) break; } - case Item::DATE_ITEM: - { - Item_temporal_literal* itp = (Item_temporal_literal*)item; - gwip->rcWorkStack.push(buildReturnedColumn(itp, *gwip, gwip->fatalParseError)); - break; - } case Item::WINDOW_FUNC_ITEM: { @@ -5513,10 +5717,6 @@ void gp_walk(const Item* item, void* arg) printf("********** received INSERT_VALUE_ITEM *********\n"); break; - case Item::Item::TYPE_HOLDER: - printf("********** received TYPE_HOLDER *********\n"); - break; - case Item::PARAM_ITEM: printf("********** received PARAM_ITEM *********\n"); break; @@ -5525,6 +5725,7 @@ void gp_walk(const Item* item, void* arg) printf("********** received TRIGGER_FIELD_ITEM *********\n"); break; + /* WIP MCOL-2178 case Item::XPATH_NODESET: printf("********** received XPATH_NODESET *********\n"); break; @@ -5536,13 +5737,17 @@ void gp_walk(const Item* item, void* arg) case Item::VIEW_FIXER_ITEM: printf("********** received VIEW_FIXER_ITEM *********\n"); break; - + */ + case Item::TYPE_HOLDER: + std::cerr << "********** received TYPE_HOLDER *********" << std::endl; + break; default: { if (gwip->condPush) { // push noop for unhandled item SimpleColumn* rc = new SimpleColumn("noop"); + rc->timeZone(gwip->thd->variables.time_zone->get_name()->ptr()); gwip->rcWorkStack.push(rc); break; } @@ -5586,7 +5791,7 @@ void parse_item (Item* item, vector& field_vec, Item** sfitempp = isp->arguments(); for (uint32_t i = 0; i < isp->argument_count(); i++) - parse_item(sfitempp[i], field_vec, hasNonSupportItem, parseInfo); + parse_item(sfitempp[i], field_vec, hasNonSupportItem, parseInfo, gwi); break; } @@ -5605,7 +5810,6 @@ void parse_item (Item* item, vector& field_vec, for (uint32_t i = 0; i < isp->argument_count(); i++) parse_item(isp->arguments()[i], field_vec, hasNonSupportItem, parseInfo, gwi); -// parse_item(sfitempp[i], field_vec, hasNonSupportItem, parseInfo); break; } @@ -5616,7 +5820,7 @@ void parse_item (Item* item, vector& field_vec, Item* cond_item; while ((cond_item = it++)) - parse_item(cond_item, field_vec, hasNonSupportItem, parseInfo); + parse_item(cond_item, field_vec, hasNonSupportItem, parseInfo, gwi); break; } @@ -5635,14 +5839,19 @@ void parse_item (Item* item, vector& field_vec, // special handling for count(*). This should not be treated as constant. if (isp->argument_count() == 1 && - (sfitempp[0]->type() == Item::INT_ITEM || - sfitempp[0]->type() == Item::STRING_ITEM || - sfitempp[0]->type() == Item::REAL_ITEM || - sfitempp[0]->type() == Item::DECIMAL_ITEM)) + ( sfitempp[0]->type() == Item::CONST_ITEM && + (sfitempp[0]->cmp_type() == INT_RESULT || + sfitempp[0]->cmp_type() == STRING_RESULT || + sfitempp[0]->cmp_type() == REAL_RESULT || + sfitempp[0]->cmp_type() == DECIMAL_RESULT) + ) + ) + { field_vec.push_back((Item_field*)item); //dummy + } for (uint32_t i = 0; i < isp->argument_count(); i++) - parse_item(sfitempp[i], field_vec, hasNonSupportItem, parseInfo); + parse_item(sfitempp[i], field_vec, hasNonSupportItem, parseInfo, gwi); break; } @@ -5670,14 +5879,14 @@ void parse_item (Item* item, vector& field_vec, Item** sfitempp = isp->arguments(); for (uint32_t i = 0; i < isp->argument_count(); i++) - parse_item(sfitempp[i], field_vec, hasNonSupportItem, parseInfo); + parse_item(sfitempp[i], field_vec, hasNonSupportItem, parseInfo, gwi); break; } else if ((*(ref->ref))->type() == Item::CACHE_ITEM) { Item_cache* isp = reinterpret_cast(*(ref->ref)); - parse_item(isp->get_example(), field_vec, hasNonSupportItem, parseInfo); + parse_item(isp->get_example(), field_vec, hasNonSupportItem, parseInfo, gwi); break; } else if ((*(ref->ref))->type() == Item::REF_ITEM) @@ -5716,7 +5925,7 @@ void parse_item (Item* item, vector& field_vec, Item_row* row = (Item_row*)item; for (uint32_t i = 0; i < row->cols(); i++) - parse_item(row->element_index(i), field_vec, hasNonSupportItem, parseInfo); + parse_item(row->element_index(i), field_vec, hasNonSupportItem, parseInfo, gwi); break; } @@ -5724,7 +5933,11 @@ void parse_item (Item* item, vector& field_vec, case Item::EXPR_CACHE_ITEM: { // item is a Item_cache_wrapper. Shouldn't get here. - printf("EXPR_CACHE_ITEM in parse_item\n"); + // WIP Why + IDEBUG(std::cerr << "EXPR_CACHE_ITEM in parse_item\n" << std::endl); + gwi->fatalParseError = true; + // DRRTUY The questionable error text. I've seen + // ERR_CORRELATED_SUB_OR string parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_SUB_QUERY_TYPE); setError(gwi->thd, ER_CHECK_NOT_IMPLEMENTED, parseErrorText); break; @@ -5739,7 +5952,7 @@ void parse_item (Item* item, vector& field_vec, } } -bool isInfiniDB(TABLE* table_ptr) +bool isMCSTable(TABLE* table_ptr) { #if (defined(_MSC_VER) && defined(_DEBUG)) || defined(SAFE_MUTEX) @@ -5761,19 +5974,24 @@ bool isInfiniDB(TABLE* table_ptr) return false; } -int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool isUnion) +int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, + SCSEP& csep, + bool isUnion, + bool isPushdownHand) { #ifdef DEBUG_WALK_COND cerr << "getSelectPlan()" << endl; #endif // by pass the derived table resolve phase of mysql - if (!(((gwi.thd->lex)->sql_command == SQLCOM_UPDATE ) || + if ( !isPushdownHand && + !(((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 ) ) && gwi.thd->derived_tables_processing) { - gwi.thd->infinidb_vtable.isUnion = false; +// TODO MCOL-2178 isUnion member only assigned, never used +// MIGR::infinidb_vtable.isUnion = false; return -1; } @@ -5821,7 +6039,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i // @bug 2123. Override large table estimate if infinidb_ordered hint was used. // @bug 2404. Always override if the infinidb_ordered_only variable is turned on. - if (gwi.thd->infinidb_vtable.override_largeside_estimate || get_ordered_only(gwi.thd)) + if (get_ordered_only(gwi.thd)) csep->overrideLargeSideEstimate(true); // @bug 5741. Set a flag when in Local PM only query mode @@ -5885,10 +6103,10 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i if (table_ptr->derived) { String str; - (table_ptr->derived->first_select())->print(gwi.thd, &str, QT_INFINIDB_DERIVED); + (table_ptr->derived->first_select())->print(gwi.thd, &str, QT_ORDINARY); SELECT_LEX* select_cursor = table_ptr->derived->first_select(); - FromSubQuery fromSub(gwi, select_cursor); + FromSubQuery fromSub(gwi, select_cursor, isPushdownHand); string alias(table_ptr->alias.str); fromSub.alias(lower(alias)); @@ -5907,11 +6125,12 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i gwi.tbList.push_back(tn); CalpontSystemCatalog::TableAliasName tan = make_aliastable("", alias, alias); gwi.tableMap[tan] = make_pair(0, table_ptr); - gwi.thd->infinidb_vtable.isUnion = true; //by-pass the 2nd pass of rnd_init +// TODO MCOL-2178 isUnion member only assigned, never used +// MIGR::infinidb_vtable.isUnion = true; //by-pass the 2nd pass of rnd_init } else if (table_ptr->view) { - View* view = new View(table_ptr->view->select_lex, &gwi); + View* view = new View(*table_ptr->view->first_select_lex(), &gwi); CalpontSystemCatalog::TableAliasName tn = make_aliastable(table_ptr->db.str, table_ptr->table_name.str, table_ptr->alias.str); view->viewName(tn); gwi.viewList.push_back(view); @@ -5920,7 +6139,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i else { // check foreign engine tables - bool infiniDB = (table_ptr->table ? isInfiniDB(table_ptr->table) : true); + bool infiniDB = (table_ptr->table ? isMCSTable(table_ptr->table) : true); // trigger system catalog cache if (infiniDB) @@ -5972,9 +6191,14 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i bool unionSel = false; + // UNION master unit check + // Existed pushdown handlers won't get in this scope + // except UNION pushdown that is to come. + // is_unit_op() give a segv for derived_handler's SELECT_LEX if (!isUnion && select_lex.master_unit()->is_unit_op()) { - gwi.thd->infinidb_vtable.isUnion = true; +// TODO MCOL-2178 isUnion member only assigned, never used +// MIGR::infinidb_vtable.isUnion = true; CalpontSelectExecutionPlan::SelectList unionVec; SELECT_LEX* select_cursor = select_lex.master_unit()->first_select(); unionSel = true; @@ -6007,7 +6231,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i union_gwi.thd = gwi.thd; uint32_t err = 0; - if ((err = getSelectPlan(union_gwi, *sl, plan, unionSel)) != 0) + if ((err = getSelectPlan(union_gwi, *sl, plan, unionSel, isPushdownHand)) != 0) return err; unionVec.push_back(SCEP(plan)); @@ -6033,7 +6257,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i csep->distinctUnionNum(distUnionNum); if (unionVec.empty()) - gwi.thd->infinidb_vtable.impossibleWhereOnUnion = true; + gwi.cs_vtable_impossible_where_on_union = true; } gwi.clauseType = WHERE; @@ -6043,7 +6267,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i // MariaDB bug 624 - without the fix_fields call, delete with join may error with "No query step". //#if MYSQL_VERSION_ID < 50172 //@bug 3039. fix fields for constants - if (!icp->fixed) + if (!icp->is_fixed()) { icp->fix_fields(gwi.thd, (Item**)&icp); } @@ -6066,8 +6290,9 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i // processing. if (gwi.thd->derived_tables_processing) { - gwi.thd->infinidb_vtable.isUnion = false; - gwi.thd->infinidb_vtable.isUpdateWithDerive = true; +// TODO MCOL-2178 isUnion member only assigned, never used +// MIGR::infinidb_vtable.isUnion = false; + gwi.cs_vtable_is_update_with_derive = true; return -1; } @@ -6087,62 +6312,63 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i #ifdef OUTER_JOIN_DEBUG List* tables = &(select_lex.top_join_list); List_iterator_fast ti(*tables); - //TABLE_LIST *inner; - //TABLE_LIST **table= (TABLE_LIST **)gwi.thd->alloc(sizeof(TABLE_LIST*) * tables->elements); - //for (TABLE_LIST **t= table + (tables->elements - 1); t >= table; t--) - // *t= ti++; - //DBUG_ASSERT(tables->elements >= 1); + TABLE_LIST **table= (TABLE_LIST **)gwi.thd->alloc(sizeof(TABLE_LIST*) * tables->elements); + for (TABLE_LIST **t= table + (tables->elements - 1); t >= table; t--) + *t= ti++; - //TABLE_LIST **end= table + tables->elements; - //for (TABLE_LIST **tbl= table; tbl < end; tbl++) - TABLE_LIST* curr; + DBUG_ASSERT(tables->elements >= 1); - while ((curr = ti++)) + TABLE_LIST **end= table + tables->elements; + for (TABLE_LIST **tbl= table; tbl < end; tbl++) { - TABLE_LIST* curr = *tbl; + TABLE_LIST* curr; - if (curr->table_name) - cerr << curr->table_name << " "; - else - cerr << curr->alias << endl; - - if (curr->outer_join) - cerr << " is inner table" << endl; - else if (curr->straight) - cerr << "straight_join" << endl; - else - cerr << "join" << endl; - - if (curr->nested_join) + while ((curr = ti++)) { - List* inners = &(curr->nested_join->join_list); - List_iterator_fast li(*inners); - TABLE_LIST** inner = (TABLE_LIST**)gwi.thd->alloc(sizeof(TABLE_LIST*) * inners->elements); + TABLE_LIST* curr = *tbl; - for (TABLE_LIST** t = inner + (inners->elements - 1); t >= inner; t--) - *t = li++; + if (curr->table_name.length) + cerr << curr->table_name.str << " "; + else + cerr << curr->alias.str << endl; - TABLE_LIST** end1 = inner + inners->elements; + if (curr->outer_join) + cerr << " is inner table" << endl; + else if (curr->straight) + cerr << "straight_join" << endl; + else + cerr << "join" << endl; - for (TABLE_LIST** tb = inner; tb < end1; tb++) + if (curr->nested_join) { - TABLE_LIST* curr1 = *tb; - cerr << curr1->alias << endl; + List* inners = &(curr->nested_join->join_list); + List_iterator_fast li(*inners); + TABLE_LIST** inner = (TABLE_LIST**)gwi.thd->alloc(sizeof(TABLE_LIST*) * inners->elements); - if (curr1->sj_on_expr) + for (TABLE_LIST** t = inner + (inners->elements - 1); t >= inner; t--) + *t = li++; + + TABLE_LIST** end1 = inner + inners->elements; + + for (TABLE_LIST** tb = inner; tb < end1; tb++) { - curr1->sj_on_expr->traverse_cond(debug_walk, &gwi, Item::POSTFIX); + TABLE_LIST* curr1 = *tb; + cerr << curr1->alias.str << endl; + + if (curr1->sj_on_expr) + { + curr1->sj_on_expr->traverse_cond(debug_walk, &gwi, Item::POSTFIX); + } } } - } - if (curr->sj_on_expr) - { - curr->sj_on_expr->traverse_cond(debug_walk, &gwi, Item::POSTFIX); + if (curr->sj_on_expr) + { + curr->sj_on_expr->traverse_cond(debug_walk, &gwi, Item::POSTFIX); + } } } - #endif uint32_t failed = buildOuterJoin(gwi, select_lex); @@ -6222,7 +6448,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i List_iterator_fast it(select_lex.item_list); Item* item; vector funcFieldVec; - string sel_cols_in_create; + string sel_cols_in_select; bool redo = false; @@ -6274,18 +6500,13 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i { boost::shared_ptr spsc(sc); - if (sel_cols_in_create.length() != 0) - sel_cols_in_create += ", "; - string fullname; String str; - ifp->print(&str, QT_INFINIDB_NO_QUOTE); + ifp->print(&str, QT_ORDINARY); fullname = str.c_ptr(); - //sel_cols_in_create += fullname; if (ifp->is_autogenerated_name) // no alias { - sel_cols_in_create += fullname + " `" + escapeBackTick(str.c_ptr()) + "`"; sc->alias(fullname); } else // alias @@ -6293,7 +6514,6 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i if (!itemAlias.empty()) sc->alias(itemAlias); - sel_cols_in_create += fullname + " `" + escapeBackTick(sc->alias().c_str()) + "`"; } if (ifp->is_autogenerated_name) @@ -6341,12 +6561,8 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i gwi.returnedCols.push_back(spac); gwi.selectCols.push_back('`' + escapeBackTick(spac->alias().c_str()) + '`'); String str(256); - item->print(&str, QT_INFINIDB_NO_QUOTE); + item->print(&str, QT_ORDINARY); - if (sel_cols_in_create.length() != 0) - sel_cols_in_create += ", "; - - sel_cols_in_create += string(str.c_ptr()) + " `" + escapeBackTick(spac->alias().c_str()) + "`"; break; } @@ -6374,7 +6590,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i uint16_t parseInfo = 0; vector tmpVec; bool hasNonSupportItem = false; - parse_item(ifp, tmpVec, hasNonSupportItem, parseInfo); + parse_item(ifp, tmpVec, hasNonSupportItem, parseInfo, &gwi); if (ifp->with_subquery() || string(ifp->func_name()) == string("") || @@ -6392,68 +6608,36 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i if (rc) { + // MCOL-2178 CS has to process determenistic functions with constant arguments. if (!hasNonSupportItem && !nonConstFunc(ifp) && !(parseInfo & AF_BIT) && tmpVec.size() == 0) { - if (isUnion || unionSel || gwi.subSelectType != CalpontSelectExecutionPlan::MAIN_SELECT || - parseInfo & SUB_BIT || select_lex.group_list.elements != 0) - { - srcp.reset(buildReturnedColumn(item, gwi, gwi.fatalParseError)); - gwi.returnedCols.push_back(srcp); + srcp.reset(buildReturnedColumn(item, gwi, gwi.fatalParseError)); + gwi.returnedCols.push_back(srcp); - if (ifp->name.length) - srcp->alias(ifp->name.str); + if (ifp->name.length) + srcp->alias(ifp->name.str); - continue; - } - - 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 ) ) - { } - else - { - redo = true; - String str; - ifp->print(&str, QT_INFINIDB_NO_QUOTE); - gwi.selectCols.push_back(string(str.c_ptr()) + " " + "`" + escapeBackTick(item->name.str) + "`"); - } - - break; + continue; } - //SRCP srcp(rc); gwi.returnedCols.push_back(srcp); - - 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 )) - { } - else - { - String str(256); - ifp->print(&str, QT_INFINIDB_NO_QUOTE); - - if (sel_cols_in_create.length() != 0) - sel_cols_in_create += ", "; - - sel_cols_in_create += string(str.c_ptr()) + " `" + ifp->name.str + "`"; - gwi.selectCols.push_back("`" + escapeBackTick(ifp->name.str) + "`"); - } } - else // InfiniDB Non support functions still go through post process for now + else // This was a vtable post-process block { hasNonSupportItem = false; uint32_t before_size = funcFieldVec.size(); - parse_item(ifp, funcFieldVec, hasNonSupportItem, parseInfo); + parse_item(ifp, funcFieldVec, hasNonSupportItem, parseInfo, &gwi); uint32_t after_size = funcFieldVec.size(); // group by func and func in subquery can not be post processed + // pushdown handler projection functions // @bug3881. set_user_var can not be treated as constant function // @bug5716. Try to avoid post process function for union query. if ((gwi.subQuery || select_lex.group_list.elements != 0 || - !csep->unionVec().empty() || isUnion) && + !csep->unionVec().empty() || isUnion || isPushdownHand ) && !hasNonSupportItem && (after_size - before_size) == 0 && - !(parseInfo & AGG_BIT) && !(parseInfo & SUB_BIT) && - string(ifp->func_name()) != "set_user_var") + !(parseInfo & AGG_BIT) && !(parseInfo & SUB_BIT) + ) { String val, *str = ifp->val_str(&val); string valStr; @@ -6526,117 +6710,111 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i return -1; } } - - //@Bug 3021. Bypass postprocess for update and delete. - //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 )) - //{} else { - // @bug 3881. Here is the real redo part. - redo = true; - // @bug 1706 - String funcStr; - ifp->print(&funcStr, QT_INFINIDB); - string valStr; - valStr.assign(funcStr.ptr(), funcStr.length()); - gwi.selectCols.push_back(valStr + " `" + escapeBackTick(ifp->name.str) + "`"); - // clear the error set by buildFunctionColumn - gwi.fatalParseError = false; - gwi.parseErrorText = ""; + Message::Args args; + args.add(ifp->func_name()); + gwi.parseErrorText = + IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORTED_FUNCTION, args); + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); + return ER_CHECK_NOT_IMPLEMENTED; } } break; - } + } // End of FUNC_ITEM - case Item::INT_ITEM: + case Item::CONST_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 )) - { } - else + switch(item->cmp_type()) { - // do not push the dummy column (mysql added) to returnedCol - if (item->name.length && string(item->name.str) == "Not_used") - continue; + case INT_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 )) + { } + else + { + // do not push the dummy column (mysql added) to returnedCol + if (item->name.length && string(item->name.str) == "Not_used") + continue; - // @bug3509. Constant column is sent to ExeMgr now. - SRCP srcp(buildReturnedColumn(item, gwi, gwi.fatalParseError)); + // @bug3509. Constant column is sent to ExeMgr now. + SRCP srcp(buildReturnedColumn(item, gwi, gwi.fatalParseError)); - if (item->name.length) - srcp->alias(item->name.str); + if (item->name.length) + srcp->alias(item->name.str); - gwi.returnedCols.push_back(srcp); + gwi.returnedCols.push_back(srcp); - Item_int* isp = reinterpret_cast(item); - ostringstream oss; - oss << isp->value << " `" << escapeBackTick(srcp->alias().c_str()) << "`"; + Item_int* isp = reinterpret_cast(item); + ostringstream oss; + oss << isp->value << " `" << escapeBackTick(srcp->alias().c_str()) << "`"; - if (sel_cols_in_create.length() != 0) - sel_cols_in_create += ", "; + gwi.selectCols.push_back(oss.str()); + } - sel_cols_in_create += oss.str(); - gwi.selectCols.push_back(oss.str()); + break; + } + + case STRING_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 )) + { } + else + { + SRCP srcp(buildReturnedColumn(item, gwi, gwi.fatalParseError)); + gwi.returnedCols.push_back(srcp); + + if (item->name.length) + srcp->alias(item->name.str); + + Item_string* isp = reinterpret_cast(item); + String val, *str = isp->val_str(&val); + string valStr; + valStr.assign(str->ptr(), str->length()); + string name = "'" + valStr + "'" + " " + "`" + escapeBackTick(srcp->alias().c_str()) + "`"; + + gwi.selectCols.push_back(name); + } + + break; + } + + case DECIMAL_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 )) + { } + else + { + SRCP srcp(buildReturnedColumn(item, gwi, gwi.fatalParseError)); + gwi.returnedCols.push_back(srcp); + + if (item->name.length) + srcp->alias(item->name.str); + + Item_decimal* isp = reinterpret_cast(item); + String val, *str = isp->val_str(&val); + string valStr; + valStr.assign(str->ptr(), str->length()); + ostringstream oss; + oss << valStr.c_str() << " `" << escapeBackTick(srcp->alias().c_str()) << "`"; + + gwi.selectCols.push_back(oss.str()); + } + + break; + } + // WIP MCOL-2178 This switch doesn't handl + // ROW_, TIME_, REAL_RESULT and if one couldn't + // project the former two REAL is possible. + // Need to test before commit. + default: + { + //noop + } } - break; - } - - case Item::STRING_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 )) - { } - else - { - SRCP srcp(buildReturnedColumn(item, gwi, gwi.fatalParseError)); - gwi.returnedCols.push_back(srcp); - - if (item->name.length) - srcp->alias(item->name.str); - - Item_string* isp = reinterpret_cast(item); - String val, *str = isp->val_str(&val); - string valStr; - valStr.assign(str->ptr(), str->length()); - string name = "'" + valStr + "'" + " " + "`" + escapeBackTick(srcp->alias().c_str()) + "`"; - - if (sel_cols_in_create.length() != 0) - sel_cols_in_create += ", "; - - sel_cols_in_create += name; - gwi.selectCols.push_back(name); - } - - break; - } - - case Item::DECIMAL_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 )) - { } - else - { - SRCP srcp(buildReturnedColumn(item, gwi, gwi.fatalParseError)); - gwi.returnedCols.push_back(srcp); - - if (item->name.length) - srcp->alias(item->name.str); - - Item_decimal* isp = reinterpret_cast(item); - String val, *str = isp->val_str(&val); - string valStr; - valStr.assign(str->ptr(), str->length()); - ostringstream oss; - oss << valStr.c_str() << " `" << escapeBackTick(srcp->alias().c_str()) << "`"; - - if (sel_cols_in_create.length() != 0) - sel_cols_in_create += ", "; - - sel_cols_in_create += oss.str(); - gwi.selectCols.push_back(oss.str()); - } - - break; - } + } // CONST_ITEM ends here case Item::NULL_ITEM: { @@ -6652,10 +6830,6 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i string name = string("null `") + escapeBackTick(srcp->alias().c_str()) + string("`") ; - if (sel_cols_in_create.length() != 0) - sel_cols_in_create += ", "; - - sel_cols_in_create += name; gwi.selectCols.push_back("null"); } @@ -6714,17 +6888,14 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i gwi.returnedCols.push_back(SRCP(rc)); String str; - sub->get_select_lex()->print(gwi.thd, &str, QT_INFINIDB_NO_QUOTE); - sel_cols_in_create += "(" + string(str.c_ptr()) + ")"; + sub->get_select_lex()->print(gwi.thd, &str, QT_ORDINARY); if (sub->name.length) { - sel_cols_in_create += "`" + escapeBackTick(sub->name.str) + "`"; gwi.selectCols.push_back(sub->name.str); } else { - sel_cols_in_create += "`" + escapeBackTick(str.c_ptr()) + "`"; gwi.selectCols.push_back("`" + escapeBackTick(str.c_ptr()) + "`"); } @@ -6764,6 +6935,23 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i gwi.returnedCols.push_back(srcp); break; } + case Item::TYPE_HOLDER: + { + if(!gwi.tbList.size()) + { + gwi.parseErrorText = "subquery with VALUES"; + gwi.fatalParseError = true; + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + else + { + std::cerr << "********** received TYPE_HOLDER *********" << std::endl; + + } + break; + } + default: { @@ -6883,7 +7071,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i } String str; - funcFieldVec[i]->print(&str, QT_INFINIDB_NO_QUOTE); + funcFieldVec[i]->print(&str, QT_ORDINARY); sc->alias(string(str.c_ptr())); //sc->tableAlias(funcFieldVec[i]->table_name); sc->tableAlias(sc->tableAlias()); @@ -6906,25 +7094,18 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i gwi.returnedCols.push_back(srcp); gwi.columnMap.insert(CalpontSelectExecutionPlan::ColumnMap::value_type(string(funcFieldVec[i]->field_name.str), srcp)); - if (sel_cols_in_create.length() != 0) - sel_cols_in_create += ", "; - string fullname; fullname = str.c_ptr(); - sel_cols_in_create += fullname + " `" + escapeBackTick(fullname.c_str()) + "`"; TABLE_LIST* tmp = (funcFieldVec[i]->cached_table ? funcFieldVec[i]->cached_table : 0); gwi.tableMap[make_aliastable(sc->schemaName(), sc->tableName(), sc->tableAlias(), sc->isInfiniDB())] = make_pair(1, tmp); } } - // post-process Order by list and expressions on select by redo phase1. only for vtable - // ignore ORDER BY clause for union select unit - string ord_cols = ""; // for normal select phase SRCP minSc; // min width projected column. for count(*) use // Group by list. not valid for union main query - if (gwi.thd->infinidb_vtable.vtable_state == THD::INFINIDB_CREATE_VTABLE && !unionSel) + if (!unionSel) { gwi.clauseType = GROUP_BY; Item* nonSupportItem = NULL; @@ -7096,10 +7277,13 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i // @bug5638. The group by column is constant but not counter, alias has to match a column // on the select list else if (!groupcol->counter_used && - (groupItem->type() == Item::INT_ITEM || - groupItem->type() == Item::STRING_ITEM || - groupItem->type() == Item::REAL_ITEM || - groupItem->type() == Item::DECIMAL_ITEM)) + (groupItem->type() == Item::CONST_ITEM && + (groupItem->cmp_type() == INT_RESULT || + groupItem->cmp_type() == STRING_RESULT || + groupItem->cmp_type() == REAL_RESULT || + groupItem->cmp_type() == DECIMAL_RESULT) + ) + ) { ReturnedColumn* rc = 0; @@ -7201,17 +7385,9 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i } } - if (gwi.thd->infinidb_vtable.vtable_state == THD::INFINIDB_CREATE_VTABLE) { SQL_I_List order_list = select_lex.order_list; ORDER* ordercol = reinterpret_cast(order_list.first); - string create_query(gwi.thd->infinidb_vtable.create_vtable_query.c_ptr()); - string select_query(gwi.thd->infinidb_vtable.select_vtable_query.c_ptr()); - string lower_create_query(gwi.thd->infinidb_vtable.create_vtable_query.c_ptr()); - string lower_select_query(gwi.thd->infinidb_vtable.select_vtable_query.c_ptr()); - boost::algorithm::to_lower(lower_create_query); - boost::algorithm::to_lower(lower_select_query); - // check if window functions are in order by. InfiniDB process order by list if // window functions are involved, either in order by or projection. @@ -7219,16 +7395,32 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i { if ((*(ordercol->item))->type() == Item::WINDOW_FUNC_ITEM) gwi.hasWindowFunc = true; + // MCOL-2166 Looking for this sorting item in GROUP_BY items list. + // Shouldn't look into this if query doesn't have GROUP BY or + // aggregations + if(isPushdownHand + && select_lex.agg_func_used() && select_lex.group_list.first + && !sortItemIsInGrouping(*ordercol->item, select_lex.group_list.first)) + { + std::ostringstream ostream; + std::ostringstream& osr = ostream; + getColNameFromItem(osr, *ordercol->item); + Message::Args args; + args.add(ostream.str()); + string emsg = IDBErrorInfo::instance()->errorMsg(ERR_NOT_GROUPBY_EXPRESSION, args); + gwi.parseErrorText = emsg; + setError(gwi.thd, ER_INTERNAL_ERROR, emsg, gwi); + return ERR_NOT_GROUPBY_EXPRESSION; + } } // re-visit the first of ordercol list ordercol = reinterpret_cast(order_list.first); - // for subquery, order+limit by will be supported in infinidb. build order by columns - // @todo union order by and limit support - if (gwi.hasWindowFunc - || gwi.subSelectType != CalpontSelectExecutionPlan::MAIN_SELECT - || ( isUnion && ordercol )) + // for subquery or pushdown query, order+limit by will be supported in CS + // union order by and limit are supported + if (gwi.hasWindowFunc || isPushdownHand || ( isUnion && ordercol ) + || gwi.subSelectType != CalpontSelectExecutionPlan::MAIN_SELECT ) { for (; ordercol; ordercol = ordercol->next) { @@ -7247,15 +7439,28 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i Item* ord_item = *(ordercol->item); // ignore not_used column on order by. - if (ord_item->type() == Item::INT_ITEM && ord_item->full_name() && string(ord_item->full_name()) == "Not_used") - continue; - else if (ord_item->type() == Item::INT_ITEM) - rc = gwi.returnedCols[((Item_int*)ord_item)->val_int() - 1]->clone(); + if ((ord_item->type() == Item::CONST_ITEM + && ord_item->cmp_type() == INT_RESULT) + && ord_item->full_name() + && !strcmp(ord_item->full_name(), "Not_used")) + { + continue; + } + else if (ord_item->type() == Item::CONST_ITEM + && ord_item->cmp_type() == INT_RESULT) + { + // WIP MCOL-2178. We should seek smallest + // column here and not just previous. + rc = gwi.returnedCols[((Item_int*)ord_item)->val_int() - 1]->clone(); + } else if (ord_item->type() == Item::SUBSELECT_ITEM) + { gwi.fatalParseError = true; + } else + { rc = buildReturnedColumn(ord_item, gwi, gwi.fatalParseError); - + } // @bug5501 try item_ptr if item can not be fixed. For some // weird dml statement state, item can not be fixed but the // infomation is available in item_ptr. @@ -7289,7 +7494,6 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i else if (!isUnion) { vector fieldVec; - bool addToSel; // the following order by is just for redo phase if (!unionSel) @@ -7302,101 +7506,14 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i while (ord_item->type() == Item::REF_ITEM) ord_item = (*((Item_ref*)ord_item)->ref); - // @bug 1706. re-construct the order by item one by one - //Item* ord_item = *(ordercol->item); - if (ord_cols.length() != 0) - ord_cols += ", "; + //ReturnedColumn* rc = 0; + // check if this order by column is on the select list + //Item_func* ifp = (Item_func*)(*(ordercol->item)); + //rc = buildFunctionColumn(ifp, gwi, gwi.fatalParseError); - addToSel = true; - string fullname; - - if (ordercol->in_field_list && ordercol->counter_used) + if (ord_item->type() == Item::FUNC_ITEM) { - ostringstream oss; - oss << ordercol->counter; - ord_cols += oss.str(); - - if (ordercol->direction != ORDER::ORDER_ASC) - ord_cols += " desc"; - - continue; - } - - else if (ord_item->type() == Item::FUNC_ITEM) - { - // @bug 2621. order by alias - if (!ord_item->is_autogenerated_name && ord_item->name.length) - { - ord_cols += ord_item->name.str; - continue; - } - - // if there's group by clause or aggregate column, check to see - // if this item or the arguments is on the GB list. - ReturnedColumn* rc = 0; - // check if this order by column is on the select list - Item_func* ifp = (Item_func*)(*(ordercol->item)); - rc = buildFunctionColumn(ifp, gwi, gwi.fatalParseError); - - if (rc) - { - for (uint32_t i = 0; i < gwi.returnedCols.size(); i++) - { - if (rc && rc->operator==(gwi.returnedCols[i].get())) - { - ostringstream oss; - oss << i + 1; - ord_cols += oss.str(); - addToSel = false; - break; - } - } - } - - if (addToSel) - { - FunctionColumn* fc = dynamic_cast(rc); - - if (fc) - { - addToSel = false; - redo = true; - string ord_func = string(ifp->func_name()) + "("; - - for (uint32_t i = 0; i < fc->functionParms().size(); i++) - { - if (i != 0) - ord_func += ","; - - for (uint32_t j = 0; j < gwi.returnedCols.size(); j++) - { - if (fc->functionParms()[i]->data()->operator==(gwi.returnedCols[j].get())) - { - ord_func += "`" + escapeBackTick(gwi.returnedCols[j]->alias().c_str()) + "`"; - continue; - } - - AggregateColumn* ac = dynamic_cast(fc->functionParms()[i]->data()); - - if (ac) - { - gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_ORDER_BY); - setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); - return ER_CHECK_NOT_IMPLEMENTED; - } - - addToSel = true; - //continue; - - } - } - - ord_func += ")"; - - if (!addToSel) - ord_cols += ord_func; - } - } + //FunctionColumn* fc = dynamic_cast(rc); } else if (ord_item->type() == Item::SUBSELECT_ITEM) { @@ -7404,7 +7521,6 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, emsg, gwi); return ER_CHECK_NOT_IMPLEMENTED; } - else if (ord_item->type() == Item::SUM_FUNC_ITEM) { ReturnedColumn* ac = 0; @@ -7428,38 +7544,12 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i if (!ret) continue; - if (ac->operator==(gwi.returnedCols[i].get())) - { - ostringstream oss; - oss << i + 1; - ord_cols += oss.str(); - addToSel = false; - break; - } } if (ac || !gwi.groupByCols.empty()) { - if (addToSel) - { - redo = true; - // @bug 3076. do not add the argument of aggregate function to the SELECT list, - // instead, add the whole column - String str; - ord_item->print(&str, QT_INFINIDB_NO_QUOTE); - - if (sel_cols_in_create.length() != 0) - sel_cols_in_create += ", "; - - sel_cols_in_create += str.c_ptr(); - //gwi.selectCols.push_back(" `" + string(str.c_ptr()) + "`"); - SRCP srcp(ac); - gwi.returnedCols.push_back(srcp); - ord_cols += " `" + escapeBackTick(str.c_ptr()) + "`"; - } - - if (ordercol->direction != ORDER::ORDER_ASC) - ord_cols += " desc"; + SRCP srcp(ac); + gwi.returnedCols.push_back(srcp); continue; } @@ -7468,13 +7558,6 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i { Item_field* field = reinterpret_cast(ord_item); ReturnedColumn* rc = buildSimpleColumn(field, gwi); - fullname = field->full_name(); -// if (field->db_name) -// fullname += string(field->db_name) + "."; -// if (field->table_name) -// fullname += string(field->table_name) + "."; -// if (field->field_name) -// fullname += string(field->field_name); for (uint32_t i = 0; i < gwi.returnedCols.size(); i++) { @@ -7486,26 +7569,13 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i continue; } - if (strcasecmp(fullname.c_str(), gwi.returnedCols[i]->alias().c_str()) == 0 || - strcasecmp(ord_item->name.str, gwi.returnedCols[i]->alias().c_str()) == 0) - { - ord_cols += string(" `") + escapeBackTick(gwi.returnedCols[i]->alias().c_str()) + '`'; - addToSel = false; - break; - } - if (sc && sc->sameColumn(rc)) { - ostringstream oss; - oss << i + 1; - ord_cols += oss.str(); - addToSel = false; break; } } } - if (addToSel) { // @bug 2719. Error out order by not on the distinct select list. if (select_lex.options & SELECT_DISTINCT) @@ -7517,7 +7587,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i bool hasNonSupportItem = false; uint16_t parseInfo = 0; - parse_item(ord_item, fieldVec, hasNonSupportItem, parseInfo); + parse_item(ord_item, fieldVec, hasNonSupportItem, parseInfo, &gwi); if (hasNonSupportItem) { @@ -7526,13 +7596,8 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i return ER_CHECK_NOT_IMPLEMENTED; } - String str; - ord_item->print(&str, QT_INFINIDB); - ord_cols += str.c_ptr(); } - if (ordercol->direction != ORDER::ORDER_ASC) - ord_cols += " desc"; } } @@ -7551,7 +7616,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i } String str; - fieldVec[i]->print(&str, QT_INFINIDB_NO_QUOTE); + fieldVec[i]->print(&str, QT_ORDINARY); sc->alias(string(str.c_ptr())); SRCP srcp(sc); uint32_t j = 0; @@ -7569,14 +7634,6 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i if (j == gwi.returnedCols.size()) { - string fullname; - - if (sel_cols_in_create.length() != 0) - sel_cols_in_create += ", "; - - fullname = str.c_ptr(); - sel_cols_in_create += fullname + " `" + escapeBackTick(fullname.c_str()) + "`"; - gwi.returnedCols.push_back(srcp); gwi.columnMap.insert(CalpontSelectExecutionPlan::ColumnMap::value_type(string(fieldVec[i]->field_name.str), srcp)); TABLE_LIST* tmp = (fieldVec[i]->cached_table ? fieldVec[i]->cached_table : 0); @@ -7661,235 +7718,29 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i gwi.returnedCols.push_back(minSc); } - if (!isUnion && !gwi.hasWindowFunc && gwi.subSelectType == CalpontSelectExecutionPlan::MAIN_SELECT) + // ORDER BY translation part + if (!isUnion && !gwi.hasWindowFunc + && gwi.subSelectType == CalpontSelectExecutionPlan::MAIN_SELECT ) { std::ostringstream vtb; vtb << "infinidb_vtable.$vtable_" << gwi.thd->thread_id; - //vtb << "$vtable_" << gwi.thd->thread_id; - // re-construct the select query and redo phase 1 - if (redo) - { - // select now() from region case. returnedCols should have minSc. - if (sel_cols_in_create.length() == 0) - { - SimpleColumn* sc = dynamic_cast(gwi.returnedCols[0].get()); - - if (sc) - sel_cols_in_create = dynamic_cast(gwi.returnedCols[0].get())->columnName(); - else - sel_cols_in_create = gwi.returnedCols[0]->alias(); - } - - // select * from derived table case - if (gwi.selectCols.empty()) - sel_cols_in_create = " * "; - - create_query = "create temporary table " + vtb.str() + " engine = aria as select " + sel_cols_in_create + " from "; - TABLE_LIST* table_ptr = select_lex.get_table_list(); - - bool firstTb = true; - - // put all tables, derived tables and views on the list - //TABLE_LIST* table_ptr = select_lex.get_table_list(); - set aliasSet; // to avoid duplicate table alias - - for (; table_ptr; table_ptr = table_ptr->next_global) - { - if (string(table_ptr->table_name.str).find("$vtable") != string::npos) - continue; - - if (table_ptr->derived) - { - if (aliasSet.find(table_ptr->alias.str) != aliasSet.end()) - continue; - - String str; - (table_ptr->derived->first_select())->print(gwi.thd, &str, QT_INFINIDB_DERIVED); - - if (!firstTb) - create_query += ", "; - - create_query += "(" + string(str.c_ptr()) + ") " + string(table_ptr->alias.str); - firstTb = false; - aliasSet.insert(table_ptr->alias.str); - } - else if (table_ptr->view) - { - if (aliasSet.find(table_ptr->alias.str) != aliasSet.end()) - continue; - - if (!firstTb) - create_query += ", "; - - create_query += string(table_ptr->db.str) + "." + string(table_ptr->table_name.str) + - string(" `") + escapeBackTick(table_ptr->alias.str) + string("`"); - aliasSet.insert(table_ptr->alias.str); - firstTb = false; - } - else - { - // table referenced by view is represented by viewAlias_tableAlias. - // consistent with item.cc field print. - if (table_ptr->referencing_view) - { - if (aliasSet.find(string(table_ptr->referencing_view->alias.str) + "_" + - string(table_ptr->alias.str)) != aliasSet.end()) - continue; - - if (!firstTb) - create_query += ", "; - - create_query += string(table_ptr->db.str) + "." + string(table_ptr->table_name.str) + string(" "); - create_query += string(" `") + - escapeBackTick(table_ptr->referencing_view->alias.str) + "_" + - escapeBackTick(table_ptr->alias.str) + string("`"); - aliasSet.insert(string(table_ptr->referencing_view->alias.str) + "_" + - string(table_ptr->alias.str)); - } - else - { - if (aliasSet.find(table_ptr->alias.str) != aliasSet.end()) - continue; - - if (!firstTb) - create_query += ", "; - - create_query += string(table_ptr->db.str) + "." + string(table_ptr->table_name.str) + string(" "); - create_query += string("`") + escapeBackTick(table_ptr->alias.str) + string("`"); - aliasSet.insert(table_ptr->alias.str); - } - - firstTb = false; - } - } - - - gwi.thd->infinidb_vtable.create_vtable_query.free(); - gwi.thd->infinidb_vtable.create_vtable_query.append(create_query.c_str(), create_query.length()); - gwi.thd->infinidb_vtable.vtable_state = THD::INFINIDB_REDO_PHASE1; // redo phase 1 - - // turn off select distinct from post process unless there're post process functions - // on the select list. - string sel_query = "select "; - - if (/*join->select_options*/select_lex.options & SELECT_DISTINCT && redo) - sel_query = "select distinct "; - else - sel_query = "select "; - - // select * from derived table... - if (gwi.selectCols.size() == 0) - sel_query += " * "; - - for (uint32_t i = 0; i < gwi.selectCols.size(); i++) - { - sel_query += gwi.selectCols[i]; - - if ( i + 1 != gwi.selectCols.size()) - sel_query += ", "; - } - - select_query.replace(lower_select_query.find("select *"), string("select *").length(), sel_query); - } - else - { - // remove order by clause in case this phase has been executed before. - // need a better fix later, like skip all the other non-optimized phase. - size_t pos = lower_select_query.find("order by"); - - if (pos != string::npos) - select_query.replace(pos, lower_select_query.length() - pos, ""); - - //select_query = "select * from " + vtb.str(); + { if (unionSel) order_list = select_lex.master_unit()->global_parameters()->order_list; ordercol = reinterpret_cast(order_list.first); - ord_cols = ""; for (; ordercol; ordercol = ordercol->next) { Item* ord_item = *(ordercol->item); - - // @bug 1706. re-construct the order by item one by one, because the ord_cols constucted so far - // is for REDO phase. - if (ord_cols.length() != 0) - ord_cols += ", "; - - if (ordercol->in_field_list && ordercol->counter_used) - { - ostringstream oss; - oss << ordercol->counter; - ord_cols += oss.str(); - } - else if (ord_item->type() == Item::NULL_ITEM) - { - // MCOL-793 Do nothing for an ORDER BY NULL - } - else if (ord_item->type() == Item::SUM_FUNC_ITEM) - { - Item_sum* ifp = (Item_sum*)(*(ordercol->item)); - ReturnedColumn* fc = buildAggregateColumn(ifp, gwi); - - for (uint32_t i = 0; i < gwi.returnedCols.size(); i++) - { - if (fc->operator==(gwi.returnedCols[i].get())) - { - ostringstream oss; - oss << i + 1; - ord_cols += oss.str(); - break; - } - } - - //continue; - } - // @bug 3518. if order by clause = selected column, use position. - else if (ord_item->name.length && ord_item->type() == Item::FIELD_ITEM) - { - Item_field* field = reinterpret_cast(ord_item); - string fullname; - - if (field->db_name) - fullname += string(field->db_name) + "."; - - if (field->table_name) - fullname += string(field->table_name) + "."; - - if (field->field_name.length) - fullname += string(field->field_name.str); - - uint32_t i = 0; - - for (i = 0; i < gwi.returnedCols.size(); i++) - { - SimpleColumn* sc = dynamic_cast(gwi.returnedCols[i].get()); - - if (sc && ((Item_field*)ord_item)->cached_table && - (strcasecmp(getViewName(((Item_field*)ord_item)->cached_table).c_str(), sc->viewName().c_str()) != 0)) - continue; - - if (strcasecmp(fullname.c_str(), gwi.returnedCols[i]->alias().c_str()) == 0 || - strcasecmp(ord_item->name.str, gwi.returnedCols[i]->alias().c_str()) == 0) - { - ostringstream oss; - oss << i + 1; - ord_cols += oss.str(); - break; - } - } - - if (i == gwi.returnedCols.size()) - ord_cols += string(" `") + escapeBackTick(ord_item->name.str) + '`'; - } - - else if (ord_item->name.length) + + if (ord_item->name.length) { // for union order by 1 case. For unknown reason, it doesn't show in_field_list - if (ord_item->type() == Item::INT_ITEM) + if (ord_item->type() == Item::CONST_ITEM + && ord_item->cmp_type() == INT_RESULT) { - ord_cols += ord_item->name.str; } else if (ord_item->type() == Item::SUBSELECT_ITEM) { @@ -7899,7 +7750,6 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i } else { - ord_cols += string(" `") + escapeBackTick(ord_item->name.str) + '`'; } } else if (ord_item->type() == Item::FUNC_ITEM) @@ -7913,7 +7763,6 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i { ostringstream oss; oss << i + 1; - ord_cols += oss.str(); break; } } @@ -7921,24 +7770,27 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i else { String str; - ord_item->print(&str, QT_INFINIDB_NO_QUOTE); - ord_cols += string(str.c_ptr()); + ord_item->print(&str, QT_ORDINARY); } - if (ordercol->direction != ORDER::ORDER_ASC) - ord_cols += " desc"; } } - if (ord_cols.length() > 0) // has order by + if ( gwi.orderByCols.size() ) // has order by { - gwi.thd->infinidb_vtable.has_order_by = true; csep->hasOrderBy(true); - ord_cols = " order by " + ord_cols; - select_query += ord_cols; + // To activate LimitedOrderBy + if(isPushdownHand) + { + csep->specHandlerProcessed(true); + } } } + // LIMIT processing part + uint64_t limitNum = std::numeric_limits::max(); + + // non-MAIN union branch if (unionSel || gwi.subSelectType != CalpontSelectExecutionPlan::MAIN_SELECT) { if (select_lex.master_unit()->global_parameters()->explicit_limit) @@ -7955,16 +7807,9 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i csep->limitNum(select->val_int()); } - if (unionSel && gwi.subSelectType == CalpontSelectExecutionPlan::MAIN_SELECT) - { - ostringstream limit; - limit << " limit "; - limit << csep->limitStart() << ", "; - limit << csep->limitNum(); - select_query += limit.str(); - } } } + // union with explicit select at the top level else if (isUnion && select_lex.explicit_limit) { if (select_lex.braces) @@ -7976,10 +7821,10 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i csep->limitNum(((Item_int*)select_lex.select_limit)->val_int()); } } + // other types of queries that have explicit LIMIT else if (select_lex.explicit_limit) { uint32_t limitOffset = 0; - uint32_t limitNum = std::numeric_limits::max(); if (join) { @@ -7990,9 +7835,9 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i // select_lex->offset_limit if not null. if (join->select_lex && join->select_lex->offset_limit && - join->select_lex->offset_limit->fixed && + join->select_lex->offset_limit->is_fixed() && join->select_lex->select_limit && - join->select_lex->select_limit->fixed) + join->select_lex->select_limit->is_fixed()) { limitOffset = join->select_lex->offset_limit->val_int(); limitNum = join->select_lex->select_limit->val_int(); @@ -8026,24 +7871,25 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i // relate to bug4848. let mysql drive limit when limit session variable set. // do not set in csep. @bug5096. ignore session limit setting for dml - if ((gwi.thd->variables.select_limit == (uint64_t) - 1 || - (gwi.thd->variables.select_limit != (uint64_t) - 1 && - gwi.thd->infinidb_vtable.vtable_state != THD::INFINIDB_CREATE_VTABLE)) && - !csep->hasOrderBy()) + if (gwi.thd->variables.select_limit == (uint64_t) - 1 && + !csep->hasOrderBy()) { csep->limitStart(limitOffset); csep->limitNum(limitNum); } - else + // Pushdown queries w ORDER BY and LIMIT + else if (isPushdownHand && csep->hasOrderBy()) { - ostringstream limit; - limit << " limit " << limitOffset << ", " << limitNum; - select_query += limit.str(); + csep->limitStart(limitOffset); + csep->limitNum(limitNum); } } - - gwi.thd->infinidb_vtable.select_vtable_query.free(); - gwi.thd->infinidb_vtable.select_vtable_query.append(select_query.c_str(), select_query.length()); + // Pushdown queries with ORDER BY w/o explicit limit + else if (isPushdownHand && csep->hasOrderBy()) + { + // We must set this to activate LimitedOrderBy in ExeMgr + csep->limitNum((uint64_t) - 2); + } // We don't currently support limit with correlated subquery if (csep->limitNum() != (uint64_t) - 1 && @@ -8054,9 +7900,9 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i setError(gwi.thd, ER_INTERNAL_ERROR, gwi.parseErrorText, gwi); return ER_CHECK_NOT_IMPLEMENTED; } - } + } // LIMIT processing finishes here - if (/*join->select_options*/select_lex.options & SELECT_DISTINCT) + if (select_lex.options & SELECT_DISTINCT) csep->distinct(true); // add the smallest column to count(*) parm. @@ -8139,7 +7985,6 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i csep->derivedTableList(gwi.derivedTbList); csep->selectSubList(selectSubList); csep->subSelectList(gwi.subselectList); - gwi.thd->infinidb_vtable.duplicate_field_name = false; clearStacks(gwi); return 0; } @@ -8149,9 +7994,11 @@ int cp_get_plan(THD* thd, SCSEP& csep) LEX* lex = thd->lex; idbassert(lex != 0); - SELECT_LEX select_lex = lex->select_lex; gp_walk_info gwi; gwi.thd = thd; + + // WIP MCOL-2178 A questionable replacement. + SELECT_LEX select_lex = *lex->first_select_lex(); int status = getSelectPlan(gwi, select_lex, csep); if (status > 0) @@ -8286,10 +8133,54 @@ int cp_get_group_plan(THD* thd, SCSEP& csep, cal_impl_if::cal_group_info& gi) return ER_INTERNAL_ERROR; else if (status < 0) return status; + // Derived table projection and filter optimization. + derivedTableOptimization(thd, csep); return 0; } +int cs_get_derived_plan(derived_handler* handler, THD* thd, SCSEP& csep, gp_walk_info& gwi) +{ + SELECT_LEX select_lex = *handler->select; + int status = getSelectPlan(gwi, select_lex, csep, false, true); + + if (status > 0) + return ER_INTERNAL_ERROR; + else if (status < 0) + return status; + +#ifdef DEBUG_WALK_COND + cerr << "---------------- cp_get_derived_plan EXECUTION PLAN ----------------" << endl; + cerr << *csep << endl ; + cerr << "-------------- EXECUTION PLAN END --------------\n" << endl; +#endif + // Derived table projection and filter optimization. + derivedTableOptimization(thd, csep); + return 0; +} + +int cs_get_select_plan(select_handler* handler, THD* thd, SCSEP& csep, gp_walk_info& gwi) +{ + SELECT_LEX select_lex = *handler->select; + int status = getSelectPlan(gwi, select_lex, csep, false, true); + + if (status > 0) + return ER_INTERNAL_ERROR; + else if (status < 0) + return status; + +#ifdef DEBUG_WALK_COND + cerr << "---------------- cp_get_select_plan EXECUTION PLAN ----------------" << endl; + cerr << *csep << endl ; + cerr << "-------------- EXECUTION PLAN END --------------\n" << endl; +#endif + // Derived table projection and filter optimization. + derivedTableOptimization(thd, csep); + + return 0; +} + + /*@brief buildConstColFromFilter- change SimpleColumn into ConstColumn*/ /*********************************************************** * DESCRIPTION: @@ -8297,6 +8188,8 @@ int cp_get_group_plan(THD* thd, SCSEP& csep, cal_impl_if::cal_group_info& gi) * filter predicate is used, e.g. * field = 'AIR', field IN ('AIR'). This utility function tries to * replace such fields with ConstantColumns using cond_pushed filters. + * TBD Take into account that originalSC SimpleColumn could be: + * SimpleColumn, ArithmeticColumn, FunctionColumn. * PARAMETERS: * originalSC SimpleColumn* removed field * gwi main strucutre @@ -8329,9 +8222,10 @@ ConstantColumn* buildConstColFromFilter(SimpleColumn* originalSC, continue; op = simpFilter->op(); + execplan::ReturnedColumn* rc = dynamic_cast(simpleCol); - if ( originalSC->sameColumn(dynamic_cast(simpleCol)) - && op.get()->op() == OP_EQ && constCol) + // The filter could have any kind of op + if ( originalSC->sameColumn(rc) ) { #ifdef DEBUG_WALK_COND cerr << "buildConstColFromFilter() replaced " << endl; @@ -8378,7 +8272,7 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro // @bug 2123. Override large table estimate if infinidb_ordered hint was used. // @bug 2404. Always override if the infinidb_ordered_only variable is turned on. - if (gwi.thd->infinidb_vtable.override_largeside_estimate || get_ordered_only(gwi.thd)) + if (get_ordered_only(gwi.thd)) csep->overrideLargeSideEstimate(true); // @bug 5741. Set a flag when in Local PM only query mode @@ -8442,10 +8336,11 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro if (table_ptr->derived) { String str; - (table_ptr->derived->first_select())->print(gwi.thd, &str, QT_INFINIDB_DERIVED); + (table_ptr->derived->first_select())->print(gwi.thd, &str, QT_ORDINARY); SELECT_LEX* select_cursor = table_ptr->derived->first_select(); - FromSubQuery fromSub(gwi, select_cursor); + // Use Pushdown handler for subquery processing + FromSubQuery fromSub(gwi, select_cursor, true); string alias(table_ptr->alias.str); fromSub.alias(lower(alias)); @@ -8464,11 +8359,13 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro gwi.tbList.push_back(tn); CalpontSystemCatalog::TableAliasName tan = make_aliastable("", alias, alias); gwi.tableMap[tan] = make_pair(0, table_ptr); -// gwi.thd->infinidb_vtable.isUnion = true; //by-pass the 2nd pass of rnd_init +// TODO MCOL-2178 isUnion member only assigned, never used +// MIGR::infinidb_vtable.isUnion = true; //by-pass the 2nd pass of rnd_init } else if (table_ptr->view) { - View* view = new View(table_ptr->view->select_lex, &gwi); + // WIP MCOL-2178 A questionable replacement. + View* view = new View(*table_ptr->view->first_select_lex(), &gwi); CalpontSystemCatalog::TableAliasName tn = make_aliastable(table_ptr->db.str, table_ptr->table_name.str, table_ptr->alias.str); view->viewName(tn); gwi.viewList.push_back(view); @@ -8477,7 +8374,7 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro else { // check foreign engine tables - bool infiniDB = (table_ptr->table ? isInfiniDB(table_ptr->table) : true); + bool infiniDB = (table_ptr->table ? isMCSTable(table_ptr->table) : true); // trigger system catalog cache if (infiniDB) @@ -8538,7 +8435,7 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro // MariaDB bug 624 - without the fix_fields call, delete with join may error with "No query step". //#if MYSQL_VERSION_ID < 50172 //@bug 3039. fix fields for constants - if (!icp->fixed) + if (!icp->is_fixed()) { icp->fix_fields(gwi.thd, (Item**)&icp); } @@ -8561,8 +8458,8 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro // processing. if (gwi.thd->derived_tables_processing) { - gwi.thd->infinidb_vtable.isUnion = false; - gwi.thd->infinidb_vtable.isUpdateWithDerive = true; +// TODO MCOL-2178 isUnion member only assigned, never used +// MIGR::infinidb_vtable.isUnion = false; return -1; } @@ -8657,8 +8554,6 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro List_iterator_fast it(*gi.groupByFields); Item* item; vector funcFieldVec; - string sel_cols_in_create; - string sel_cols_in_select; bool redo = false; // empty rcWorkStack and ptWorkStack. They should all be empty by now. @@ -8718,18 +8613,13 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro boost::shared_ptr spcc(constCol); boost::shared_ptr spsc(sc); - if (sel_cols_in_create.length() != 0) - sel_cols_in_create += ", "; - string fullname; String str; - ifp->print(&str, QT_INFINIDB_NO_QUOTE); + ifp->print(&str, QT_ORDINARY); fullname = str.c_ptr(); - //sel_cols_in_create += fullname; if (ifp->is_autogenerated_name) // no alias { - sel_cols_in_create += fullname + " `" + escapeBackTick(str.c_ptr()) + "`"; sc->alias(fullname); } else // alias @@ -8737,7 +8627,6 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro if (!itemAlias.empty()) sc->alias(itemAlias); - sel_cols_in_create += fullname + " `" + escapeBackTick(sc->alias().c_str()) + "`"; } if (ifp->is_autogenerated_name) @@ -8798,12 +8687,8 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro gwi.selectCols.push_back('`' + escapeBackTick(spac->alias().c_str()) + '`'); String str(256); - item->print(&str, QT_INFINIDB_NO_QUOTE); + item->print(&str, QT_ORDINARY); - if (sel_cols_in_create.length() != 0) - sel_cols_in_create += ", "; - - sel_cols_in_create += string(str.c_ptr()) + " `" + escapeBackTick(spac->alias().c_str()) + "`"; break; } @@ -8831,7 +8716,7 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro uint16_t parseInfo = 0; vector tmpVec; bool hasNonSupportItem = false; - parse_item(ifp, tmpVec, hasNonSupportItem, parseInfo); + parse_item(ifp, tmpVec, hasNonSupportItem, parseInfo, &gwi); if (ifp->with_subquery() || string(ifp->func_name()) == string("") || @@ -8872,7 +8757,7 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro { redo = true; String str; - ifp->print(&str, QT_INFINIDB_NO_QUOTE); + ifp->print(&str, QT_ORDINARY); gwi.selectCols.push_back(string(str.c_ptr()) + " " + "`" + escapeBackTick(item->name.str) + "`"); } @@ -8887,12 +8772,8 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro else { String str(256); - ifp->print(&str, QT_INFINIDB_NO_QUOTE); + ifp->print(&str, QT_ORDINARY); - if (sel_cols_in_create.length() != 0) - sel_cols_in_create += ", "; - - sel_cols_in_create += string(str.c_ptr()) + " `" + ifp->name.str + "`"; gwi.selectCols.push_back("`" + escapeBackTick(ifp->name.str) + "`"); } } @@ -8996,7 +8877,7 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro redo = true; // @bug 1706 String funcStr; - ifp->print(&funcStr, QT_INFINIDB); + ifp->print(&funcStr, QT_ORDINARY); gwi.selectCols.push_back(string(funcStr.c_ptr()) + " `" + escapeBackTick(ifp->name.str) + "`"); // clear the error set by buildFunctionColumn gwi.fatalParseError = false; @@ -9007,97 +8888,98 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro break; } - case Item::INT_ITEM: + case Item::CONST_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 )) - { } - else + switch(item->cmp_type()) { - // do not push the dummy column (mysql added) to returnedCol - if (item->name.length && string(item->name.str) == "Not_used") - continue; + case INT_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 )) + { } + else + { + // do not push the dummy column (mysql added) to returnedCol + if (item->name.length && string(item->name.str) == "Not_used") + continue; - // @bug3509. Constant column is sent to ExeMgr now. - SRCP srcp(buildReturnedColumn(item, gwi, gwi.fatalParseError)); + // @bug3509. Constant column is sent to ExeMgr now. + SRCP srcp(buildReturnedColumn(item, gwi, gwi.fatalParseError)); - if (item->name.length) - srcp->alias(item->name.str); + if (item->name.length) + srcp->alias(item->name.str); - gwi.returnedCols.push_back(srcp); + gwi.returnedCols.push_back(srcp); - Item_int* isp = reinterpret_cast(item); - ostringstream oss; - oss << isp->value << " `" << escapeBackTick(srcp->alias().c_str()) << "`"; + Item_int* isp = reinterpret_cast(item); + ostringstream oss; + oss << isp->value << " `" << escapeBackTick(srcp->alias().c_str()) << "`"; - if (sel_cols_in_create.length() != 0) - sel_cols_in_create += ", "; + gwi.selectCols.push_back(oss.str()); + } - sel_cols_in_create += oss.str(); - gwi.selectCols.push_back(oss.str()); + break; + } + + case STRING_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 )) + { } + else + { + SRCP srcp(buildReturnedColumn(item, gwi, gwi.fatalParseError)); + gwi.returnedCols.push_back(srcp); + + if (item->name.length) + srcp->alias(item->name.str); + + Item_string* isp = reinterpret_cast(item); + String val, *str = isp->val_str(&val); + string valStr; + valStr.assign(str->ptr(), str->length()); + string name = "'" + valStr + "'" + " " + "`" + escapeBackTick(srcp->alias().c_str()) + "`"; + + gwi.selectCols.push_back(name); + } + + break; + } + + case DECIMAL_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 )) + { } + else + { + SRCP srcp(buildReturnedColumn(item, gwi, gwi.fatalParseError)); + gwi.returnedCols.push_back(srcp); + + if (item->name.length) + srcp->alias(item->name.str); + + Item_decimal* isp = reinterpret_cast(item); + String val, *str = isp->val_str(&val); + string valStr; + valStr.assign(str->ptr(), str->length()); + ostringstream oss; + oss << valStr.c_str() << " `" << escapeBackTick(srcp->alias().c_str()) << "`"; + + gwi.selectCols.push_back(oss.str()); + } + + break; + } + default: + // WIP MCOL-2178 Same thing as for getSelectPlan + { + // noop + } } - break; - } - - case Item::STRING_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 )) - { } - else - { - SRCP srcp(buildReturnedColumn(item, gwi, gwi.fatalParseError)); - gwi.returnedCols.push_back(srcp); - - if (item->name.length) - srcp->alias(item->name.str); - - Item_string* isp = reinterpret_cast(item); - String val, *str = isp->val_str(&val); - string valStr; - valStr.assign(str->ptr(), str->length()); - string name = "'" + valStr + "'" + " " + "`" + escapeBackTick(srcp->alias().c_str()) + "`"; - - if (sel_cols_in_create.length() != 0) - sel_cols_in_create += ", "; - - sel_cols_in_create += name; - gwi.selectCols.push_back(name); - } - - break; - } - - case Item::DECIMAL_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 )) - { } - else - { - SRCP srcp(buildReturnedColumn(item, gwi, gwi.fatalParseError)); - gwi.returnedCols.push_back(srcp); - - if (item->name.length) - srcp->alias(item->name.str); - - Item_decimal* isp = reinterpret_cast(item); - String val, *str = isp->val_str(&val); - string valStr; - valStr.assign(str->ptr(), str->length()); - ostringstream oss; - oss << valStr.c_str() << " `" << escapeBackTick(srcp->alias().c_str()) << "`"; - - if (sel_cols_in_create.length() != 0) - sel_cols_in_create += ", "; - - sel_cols_in_create += oss.str(); - gwi.selectCols.push_back(oss.str()); - } - - break; - } + } // CONST_ITEM ends here case Item::NULL_ITEM: { + // WIP MCOL-2178 Check for NULL in projection. /*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 ) ) { } else @@ -9171,19 +9053,13 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro rc->alias(sub->name.str); gwi.returnedCols.push_back(SRCP(rc)); - String str; - sub->get_select_lex()->print(gwi.thd, &str, QT_INFINIDB_NO_QUOTE); - sel_cols_in_create += "(" + string(str.c_ptr()) + ")"; if (sub->name.length) { - sel_cols_in_create += "`" + escapeBackTick(sub->name.str) + "`"; gwi.selectCols.push_back(sub->name.str); } else { - sel_cols_in_create += "`" + escapeBackTick(str.c_ptr()) + "`"; - gwi.selectCols.push_back("`" + escapeBackTick(str.c_ptr()) + "`"); } break; @@ -9340,7 +9216,7 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro } String str; - funcFieldVec[i]->print(&str, QT_INFINIDB_NO_QUOTE); + funcFieldVec[i]->print(&str, QT_ORDINARY); sc->alias(string(str.c_ptr())); //sc->tableAlias(funcFieldVec[i]->table_name); sc->tableAlias(sc->tableAlias()); @@ -9363,12 +9239,8 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro gwi.returnedCols.push_back(srcp); gwi.columnMap.insert(CalpontSelectExecutionPlan::ColumnMap::value_type(string(funcFieldVec[i]->field_name.str), srcp)); - if (sel_cols_in_create.length() != 0) - sel_cols_in_create += ", "; - string fullname; fullname = str.c_ptr(); - sel_cols_in_create += fullname + " `" + escapeBackTick(fullname.c_str()) + "`"; TABLE_LIST* tmp = (funcFieldVec[i]->cached_table ? funcFieldVec[i]->cached_table : 0); gwi.tableMap[make_aliastable(sc->schemaName(), sc->tableName(), sc->tableAlias(), sc->isInfiniDB())] = make_pair(1, tmp); @@ -9381,7 +9253,7 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro SRCP minSc; // min width projected column. for count(*) use // Group by list. not valid for union main query - if (gwi.thd->infinidb_vtable.vtable_state == THD::INFINIDB_CREATE_VTABLE && !unionSel) + if (!unionSel) { gwi.clauseType = GROUP_BY; Item* nonSupportItem = NULL; @@ -9553,10 +9425,14 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro // @bug5638. The group by column is constant but not counter, alias has to match a column // on the select list else if (!groupcol->counter_used && - (groupItem->type() == Item::INT_ITEM || - groupItem->type() == Item::STRING_ITEM || - groupItem->type() == Item::REAL_ITEM || - groupItem->type() == Item::DECIMAL_ITEM)) + (groupItem->type() == Item::CONST_ITEM && + (groupItem->cmp_type() == INT_RESULT || + groupItem->cmp_type() == STRING_RESULT || + groupItem->cmp_type() == REAL_RESULT || + groupItem->cmp_type() == DECIMAL_RESULT) + ) + ) + { ReturnedColumn* rc = 0; @@ -9659,15 +9535,9 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro } // GROUP processing ends here - if (gwi.thd->infinidb_vtable.vtable_state == THD::INFINIDB_CREATE_VTABLE) + // ORDER BY processing starts here { ORDER* ordercol = reinterpret_cast(gi.groupByOrder); - string create_query(gwi.thd->infinidb_vtable.create_vtable_query.c_ptr()); - string select_query(gwi.thd->infinidb_vtable.select_vtable_query.c_ptr()); - string lower_create_query(gwi.thd->infinidb_vtable.create_vtable_query.c_ptr()); - string lower_select_query(gwi.thd->infinidb_vtable.select_vtable_query.c_ptr()); - boost::algorithm::to_lower(lower_create_query); - boost::algorithm::to_lower(lower_select_query); // check if window functions are in order by. InfiniDB process order by list if @@ -9703,12 +9573,22 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro bool nonAggField = true; // ignore not_used column on order by. - if (ord_item->type() == Item::INT_ITEM && ord_item->full_name() && string(ord_item->full_name()) == "Not_used") + if ((ord_item->type() == Item::CONST_ITEM + && ord_item->cmp_type() == INT_RESULT) + && ord_item->full_name() + && !strcmp(ord_item->full_name(), "Not_used")) + { continue; - else if (ord_item->type() == Item::INT_ITEM) + } + else if (ord_item->type() == Item::CONST_ITEM + && ord_item->cmp_type() == INT_RESULT) + { rc = gwi.returnedCols[((Item_int*)ord_item)->val_int() - 1]->clone(); + } else if (ord_item->type() == Item::SUBSELECT_ITEM) + { gwi.fatalParseError = true; + } else if (ordercol->in_field_list && ord_item->type() == Item::FIELD_ITEM) { rc = buildReturnedColumn(ord_item, gwi, gwi.fatalParseError); @@ -9759,26 +9639,9 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro // this ORDER BY item. if ( iter == gwi.groupByCols.end() ) { - Item_ident* iip = reinterpret_cast(ord_item); std::ostringstream ostream; - ostream << "'"; - - if (iip->db_name) - ostream << iip->db_name << '.'; - else - ostream << "unknown db" << '.'; - - if (iip->table_name) - ostream << iip->table_name << '.'; - else - ostream << "unknown table" << '.'; - - if (iip->field_name.length) - ostream << iip->field_name.str; - else - ostream << "unknown field"; - - ostream << "'"; + std::ostringstream& osr = ostream; + getColNameFromItem(osr, *ordercol->item); Message::Args args; args.add(ostream.str()); string emsg = IDBErrorInfo::instance()->errorMsg(ERR_NOT_GROUPBY_EXPRESSION, args); @@ -9911,30 +9774,11 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro std::ostringstream vtb; vtb << "infinidb_vtable.$vtable_" << gwi.thd->thread_id; - //vtb << "$vtable_" << gwi.thd->thread_id; // re-construct the select query and redo phase 1 if (redo) { - // select now() from region case. returnedCols should have minSc. - if (sel_cols_in_create.length() == 0) - { - SimpleColumn* sc = dynamic_cast(gwi.returnedCols[0].get()); - - if (sc) - sel_cols_in_create = dynamic_cast(gwi.returnedCols[0].get())->columnName(); - else - sel_cols_in_create = gwi.returnedCols[0]->alias(); - } - - // select * from derived table case - if (gwi.selectCols.empty()) - sel_cols_in_create = " * "; - - create_query = "create temporary table " + vtb.str() + " engine = aria as select " + sel_cols_in_create + " from "; TABLE_LIST* table_ptr = gi.groupByTables; - bool firstTb = true; - // put all tables, derived tables and views on the list //TABLE_LIST* table_ptr = select_lex.get_table_list(); set aliasSet; // to avoid duplicate table alias @@ -9949,14 +9793,6 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro if (aliasSet.find(table_ptr->alias.str) != aliasSet.end()) continue; - String str; - (table_ptr->derived->first_select())->print(gwi.thd, &str, QT_INFINIDB_DERIVED); - - if (!firstTb) - create_query += ", "; - - create_query += "(" + string(str.c_ptr()) + ") " + string(table_ptr->alias.str); - firstTb = false; aliasSet.insert(table_ptr->alias.str); } else if (table_ptr->view) @@ -9964,13 +9800,7 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro if (aliasSet.find(table_ptr->alias.str) != aliasSet.end()) continue; - if (!firstTb) - create_query += ", "; - - create_query += string(table_ptr->db.str) + "." + string(table_ptr->table_name.str) + - string(" `") + escapeBackTick(table_ptr->alias.str) + string("`"); aliasSet.insert(table_ptr->alias.str); - firstTb = false; } else { @@ -9982,13 +9812,6 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro string(table_ptr->alias.str)) != aliasSet.end()) continue; - if (!firstTb) - create_query += ", "; - - create_query += string(table_ptr->db.str) + "." + string(table_ptr->table_name.str) + string(" "); - create_query += string(" `") + - escapeBackTick(table_ptr->referencing_view->alias.str) + "_" + - escapeBackTick(table_ptr->alias.str) + string("`"); aliasSet.insert(string(table_ptr->referencing_view->alias.str) + "_" + string(table_ptr->alias.str)); } @@ -9997,83 +9820,31 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro if (aliasSet.find(table_ptr->alias.str) != aliasSet.end()) continue; - if (!firstTb) - create_query += ", "; - - create_query += string(table_ptr->db.str) + "." + string(table_ptr->table_name.str) + string(" "); - create_query += string("`") + escapeBackTick(table_ptr->alias.str) + string("`"); aliasSet.insert(table_ptr->alias.str); } - firstTb = false; } } - - gwi.thd->infinidb_vtable.create_vtable_query.free(); - gwi.thd->infinidb_vtable.create_vtable_query.append(create_query.c_str(), create_query.length()); - gwi.thd->infinidb_vtable.vtable_state = THD::INFINIDB_REDO_PHASE1; // redo phase 1 - - // turn off select distinct from post process unless there're post process functions - // on the select list. - string sel_query = "select "; - - if (gi.groupByDistinct && redo) - sel_query = "select distinct "; - else - sel_query = "select "; - - // select * from derived table... - if (gwi.selectCols.size() == 0) - sel_query += " * "; - - for (uint32_t i = 0; i < gwi.selectCols.size(); i++) - { - sel_query += gwi.selectCols[i]; - - if ( i + 1 != gwi.selectCols.size()) - sel_query += ", "; - } - - //select_query.replace(lower_select_query.find("select *"), string("select *").length(), sel_query); } else { // remove order by clause in case this phase has been executed before. // need a better fix later, like skip all the other non-optimized phase. - size_t pos = lower_select_query.find("order by"); - if (pos != string::npos) - select_query.replace(pos, lower_select_query.length() - pos, ""); - - //select_query = "select * from " + vtb.str(); // MCOL-1052 if (unionSel) { ordercol = reinterpret_cast(gi.groupByOrder); - //order_list = gi.groupByOrder; } else ordercol = 0; - ord_cols = ""; - for (; ordercol; ordercol = ordercol->next) { Item* ord_item = *(ordercol->item); - // @bug 1706. re-construct the order by item one by one, because the ord_cols constucted so far - // is for REDO phase. - if (ord_cols.length() != 0) - ord_cols += ", "; - - if (ordercol->in_field_list && ordercol->counter_used) - { - ostringstream oss; - oss << ordercol->counter; - ord_cols += oss.str(); - } - else if (ord_item->type() == Item::NULL_ITEM) + if (ord_item->type() == Item::NULL_ITEM) { // MCOL-793 Do nothing for an ORDER BY NULL } @@ -10137,7 +9908,8 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro else if (ord_item->name.length) { // for union order by 1 case. For unknown reason, it doesn't show in_field_list - if (ord_item->type() == Item::INT_ITEM) + if (ord_item->type() == Item::CONST_ITEM + && ord_item->cmp_type() == INT_RESULT) { ord_cols += ord_item->name.str; } @@ -10171,7 +9943,7 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro else { String str; - ord_item->print(&str, QT_INFINIDB_NO_QUOTE); + ord_item->print(&str, QT_ORDINARY); ord_cols += string(str.c_ptr()); } @@ -10182,7 +9954,6 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro if ( gwi.orderByCols.size() ) // has order by { - gwi.thd->infinidb_vtable.has_order_by = true; csep->hasOrderBy(true); csep->specHandlerProcessed(true); } @@ -10209,9 +9980,6 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro csep->limitStart(((Item_int*)gi.groupByTables->select_lex->offset_limit)->val_int()); } - //gwi.thd->infinidb_vtable.select_vtable_query.free(); - //gwi.thd->infinidb_vtable.select_vtable_query.append(select_query.c_str(), select_query.length()); - // We don't currently support limit with correlated subquery if (csep->limitNum() != (uint64_t) - 1 && gwi.subQuery && !gwi.correlatedTbNameVec.empty()) @@ -10307,7 +10075,6 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro csep->derivedTableList(gwi.derivedTbList); csep->selectSubList(selectSubList); csep->subSelectList(gwi.subselectList); - gwi.thd->infinidb_vtable.duplicate_field_name = false; clearStacks(gwi); return 0; } diff --git a/dbcon/mysql/ha_calpont_impl.cpp b/dbcon/mysql/ha_calpont_impl.cpp index bb08c6cb9..9acb288b7 100644 --- a/dbcon/mysql/ha_calpont_impl.cpp +++ b/dbcon/mysql/ha_calpont_impl.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2014 InfiniDB, Inc. + /* Copyright (C) 2014 InfiniDB, Inc. Copyright (C) 2019 MariaDB Corporaton This program is free software; you can redistribute it and/or @@ -80,6 +80,7 @@ using namespace execplan; using namespace dataconvert; #include "sm.h" +#include "ha_mcs_pushdown.h" #include "bytestream.h" #include "messagequeue.h" @@ -168,8 +169,6 @@ static const string interval_names[] = const unsigned NONSUPPORTED_ERR_THRESH = 2000; -//TODO: make this session-safe (put in connMap?) -//vector rmParms; ResourceManager* rm = ResourceManager::instance(); bool useHdfs = rm->useHdfs(); @@ -272,8 +271,8 @@ void storeNumericField(Field** f, int64_t value, CalpontSystemCatalog::ColType& // @bug4388 stick to InfiniDB's scale in case mysql gives wrong scale due // to create vtable limitation. - if (f2->dec < ct.scale) - f2->dec = ct.scale; + //if (f2->dec < ct.scale) + // f2->dec = ct.scale; char buf[256]; dataconvert::DataConvert::decimalToString(value, (unsigned)ct.scale, buf, 256, ct.colDataType); @@ -578,10 +577,6 @@ int fetchNextRow(uchar* buf, cal_table_info& ti, cal_connection_info* ci, bool h * At a later date we should set this more intelligently * based on the result set. */ - /* MCOL-683: UTF-8 datetime no msecs is 57, this sometimes happens! */ -// if (((*f)->field_length > 19) && ((*f)->field_length != 57)) -// (*f)->field_length = strlen(tmp); - Field_varstring* f2 = (Field_varstring*)*f; f2->store(tmp, strlen(tmp), f2->charset()); break; @@ -743,17 +738,11 @@ int fetchNextRow(uchar* buf, cal_table_info& ti, cal_connection_info* ci, bool h if (dl == std::numeric_limits::infinity()) continue; - //int64_t* icvp = (int64_t*)&dl; - //intColVal = *icvp; Field_float* f2 = (Field_float*)*f; // bug 3485, reserve enough space for the longest float value // -3.402823466E+38 to -1.175494351E-38, 0, and // 1.175494351E-38 to 3.402823466E+38. - (*f)->field_length = 40; - //float float_val = *(float*)(&value); - //f2->store(float_val); - if (f2->decimals() < (uint32_t)row.getScale(s)) - f2->dec = (uint32_t)row.getScale(s); + (*f)->field_length = 40; f2->store(dl); @@ -761,9 +750,6 @@ int fetchNextRow(uchar* buf, cal_table_info& ti, cal_connection_info* ci, bool h *(*f)->null_ptr &= ~(*f)->null_bit; break; - - //storeNumericField(f, intColVal, colType); - //break; } case CalpontSystemCatalog::DOUBLE: @@ -778,14 +764,7 @@ int fetchNextRow(uchar* buf, cal_table_info& ti, cal_connection_info* ci, bool h // bug 3483, reserve enough space for the longest double value // -1.7976931348623157E+308 to -2.2250738585072014E-308, 0, and // 2.2250738585072014E-308 to 1.7976931348623157E+308. - (*f)->field_length = 310; - //double double_val = *(double*)(&value); - //f2->store(double_val); - if ((f2->decimals() == DECIMAL_NOT_SPECIFIED && row.getScale(s) > 0) - || f2->decimals() < row.getScale(s)) - { - f2->dec = row.getScale(s); - } + (*f)->field_length = 310; f2->store(dl); @@ -793,12 +772,6 @@ int fetchNextRow(uchar* buf, cal_table_info& ti, cal_connection_info* ci, bool h *(*f)->null_ptr &= ~(*f)->null_bit; break; - - - //int64_t* icvp = (int64_t*)&dl; - //intColVal = *icvp; - //storeNumericField(f, intColVal, colType); - //break; } case CalpontSystemCatalog::LONGDOUBLE: @@ -815,12 +788,6 @@ int fetchNextRow(uchar* buf, cal_table_info& ti, cal_connection_info* ci, bool h { char buf[310]; Field_new_decimal* f2 = (Field_new_decimal*)*f; - if ((f2->decimals() == DECIMAL_NOT_SPECIFIED && row.getScale(s) > 0) - || f2->decimals() < row.getScale(s)) - { - f2->dec = row.getScale(s); - } -// dl /= pow(10.0, (double)f2->dec); snprintf(buf, 310, "%.20Lg", dl); f2->store(buf, strlen(buf), f2->charset()); if ((*f)->null_ptr) @@ -836,12 +803,6 @@ int fetchNextRow(uchar* buf, cal_table_info& ti, cal_connection_info* ci, bool h // 2.2250738585072014E-308 to 1.7976931348623157E+308. (*f)->field_length = 310; - if ((f2->decimals() == DECIMAL_NOT_SPECIFIED && row.getScale(s) > 0) - || f2->decimals() < row.getScale(s)) - { - f2->dec = row.getScale(s); - } - f2->store(static_cast(dl)); if ((*f)->null_ptr) *(*f)->null_ptr &= ~(*f)->null_bit; @@ -1215,7 +1176,7 @@ vector getOnUpdateTimestampColumns(string& schema, string& tableName, in return returnVal; } -uint32_t doUpdateDelete(THD* thd) +uint32_t doUpdateDelete(THD* thd, gp_walk_info& gwi) { if (get_fe_conn_info_ptr() == NULL) set_fe_conn_info_ptr((void*)new cal_connection_info()); @@ -1232,7 +1193,6 @@ uint32_t doUpdateDelete(THD* thd) //@Bug 4387. Check BRM status before start statement. boost::scoped_ptr dbrmp(new DBRM()); int rc = dbrmp->isReadWrite(); - thd->infinidb_vtable.isInfiniDBDML = true; if (rc != 0 ) { @@ -1314,7 +1274,6 @@ uint32_t doUpdateDelete(THD* thd) } // @bug 1127. Re-construct update stmt using lex instead of using the original query. -// string dmlStmt=""; string dmlStmt = string(idb_mysql_query_str(thd)); string schemaName; string tableName(""); @@ -1332,28 +1291,16 @@ uint32_t doUpdateDelete(THD* thd) { ColumnAssignment* columnAssignmentPtr; Item_field* item; -// TABLE_LIST* table_ptr = thd->lex->select_lex.get_table_list(); - List_iterator_fast field_it(thd->lex->select_lex.item_list); + List_iterator_fast field_it(thd->lex->first_select_lex()->item_list); List_iterator_fast value_it(thd->lex->value_list); -// dmlStmt += "update "; updateCP->queryType(CalpontSelectExecutionPlan::UPDATE); ci->stats.fQueryType = updateCP->queryType(); uint32_t cnt = 0; tr1::unordered_set timeStampColumnNames; -// for (; table_ptr; table_ptr= table_ptr->next_local) -// { -// dmlStmt += string(table_ptr->table_name); -// if (table_ptr->next_local) -// dmlStmt += ", "; -// } - -// dmlStmt += " set "; - while ((item = (Item_field*) field_it++)) { cnt++; -// dmlStmt += string(item->name) + "="; string tmpTableName = bestTableName(item); @@ -1402,22 +1349,34 @@ uint32_t doUpdateDelete(THD* thd) Item* value = value_it++; - if (value->type() == Item::STRING_ITEM) + if (value->type() == Item::CONST_ITEM) { - //@Bug 2587 use val_str to replace value->name to get rid of 255 limit - String val, *str; - str = value->val_str(&val); - columnAssignmentPtr->fScalarExpression.assign(str->ptr(), str->length()); - columnAssignmentPtr->fFromCol = false; + if (value->cmp_type() == STRING_RESULT) + { + //@Bug 2587 use val_str to replace value->name to get rid of 255 limit + String val, *str; + str = value->val_str(&val); + columnAssignmentPtr->fScalarExpression.assign(str->ptr(), str->length()); + columnAssignmentPtr->fFromCol = false; + } + else if (value->cmp_type() == INT_RESULT) + { + std::ostringstream oss; + + if (value->unsigned_flag) + { + oss << value->val_uint(); + } + else + { + oss << value->val_int(); + } + + columnAssignmentPtr->fScalarExpression = oss.str(); + columnAssignmentPtr->fFromCol = false; + } } - else if ( value->type() == Item::VARBIN_ITEM ) - { - String val, *str; - str = value->val_str(&val); - columnAssignmentPtr->fScalarExpression.assign(str->ptr(), str->length()); - columnAssignmentPtr->fFromCol = false; - } - else if ( value->type() == Item::FUNC_ITEM ) + else if ( value->type() == Item::FUNC_ITEM ) { //Bug 2092 handle negative values Item_func* ifp = (Item_func*)value; @@ -1482,23 +1441,6 @@ uint32_t doUpdateDelete(THD* thd) } } } - else if ( value->type() == Item::INT_ITEM ) - { - std::ostringstream oss; - - if (value->unsigned_flag) - { - oss << value->val_uint(); - } - else - { - oss << value->val_int(); - } - -// dmlStmt += oss.str(); - columnAssignmentPtr->fScalarExpression = oss.str(); - columnAssignmentPtr->fFromCol = false; - } else if ( value->type() == Item::FIELD_ITEM) { isFromCol = true; @@ -1562,7 +1504,6 @@ uint32_t doUpdateDelete(THD* thd) setError(thd, ER_INTERNAL_ERROR, logging::IDBErrorInfo::instance()->errorMsg(ERR_WF_UPDATE)); return ER_CHECK_NOT_IMPLEMENTED; - //return 0; } else { @@ -1582,8 +1523,6 @@ uint32_t doUpdateDelete(THD* thd) } colAssignmentListPtr->push_back ( columnAssignmentPtr ); -// if (cnt < thd->lex->select_lex.item_list.elements) -// dmlStmt += ", "; } // Support for on update current_timestamp() for timestamp fields @@ -1608,7 +1547,6 @@ uint32_t doUpdateDelete(THD* thd) } else { -// dmlStmt = string(idb_mysql_query_str(thd)); updateCP->queryType(CalpontSelectExecutionPlan::DELETE); ci->stats.fQueryType = updateCP->queryType(); } @@ -1627,7 +1565,7 @@ uint32_t doUpdateDelete(THD* thd) } else { - first_table = (TABLE_LIST*) thd->lex->select_lex.table_list.first; + first_table = (TABLE_LIST*) thd->lex->first_select_lex()->table_list.first; aTableName.schema = first_table->table->s->db.str; aTableName.table = first_table->table->s->table_name.str; } @@ -1640,7 +1578,6 @@ uint32_t doUpdateDelete(THD* thd) } catch (IDBExcept& ie) { -// setError(thd, ER_UNKNOWN_TABLE, ie.what()); setError(thd, ER_INTERNAL_ERROR, ie.what()); return ER_INTERNAL_ERROR; } @@ -1678,9 +1615,9 @@ uint32_t doUpdateDelete(THD* thd) } else if ((thd->lex)->sql_command == SQLCOM_DELETE_MULTI) //@Bug 6121 error out on multi tables delete. { - if ( (thd->lex->select_lex.join) != 0) + if ( (thd->lex->first_select_lex()->join) != 0) { - multi_delete* deleteTable = (multi_delete*)((thd->lex->select_lex.join)->result); + multi_delete* deleteTable = (multi_delete*)((thd->lex->first_select_lex()->join)->result); first_table = (TABLE_LIST*) deleteTable->get_tables(); if (deleteTable->get_num_of_tables() == 1) @@ -1703,7 +1640,7 @@ uint32_t doUpdateDelete(THD* thd) } else { - first_table = (TABLE_LIST*) thd->lex->select_lex.table_list.first; + first_table = (TABLE_LIST*) thd->lex->first_select_lex()->table_list.first; schemaName = first_table->table->s->db.str; tableName = first_table->table->s->table_name.str; aliasName = first_table->alias.str; @@ -1714,7 +1651,7 @@ uint32_t doUpdateDelete(THD* thd) } else { - first_table = (TABLE_LIST*) thd->lex->select_lex.table_list.first; + first_table = (TABLE_LIST*) thd->lex->first_select_lex()->table_list.first; schemaName = first_table->table->s->db.str; tableName = first_table->table->s->table_name.str; aliasName = first_table->alias.str; @@ -1747,16 +1684,16 @@ uint32_t doUpdateDelete(THD* thd) if (( (thd->lex)->sql_command == SQLCOM_UPDATE ) || ( (thd->lex)->sql_command == SQLCOM_UPDATE_MULTI ) ) { - items = (thd->lex->select_lex.item_list); - thd->lex->select_lex.item_list = thd->lex->value_list; + items = (thd->lex->first_select_lex()->item_list); + thd->lex->first_select_lex()->item_list = thd->lex->value_list; } - select_lex = lex->select_lex; + select_lex = *lex->first_select_lex(); //@Bug 2808 Error out on order by or limit clause //@bug5096. support dml limit. - if (/*( select_lex.explicit_limit ) || */( select_lex.order_list.elements != 0 ) ) + if (( thd->lex->first_select_lex()->order_list.elements != 0 ) ) { string emsg("DML Statement with order by clause is not currently supported."); thd->raise_error_printf(ER_INTERNAL_ERROR, emsg.c_str()); @@ -1765,13 +1702,8 @@ uint32_t doUpdateDelete(THD* thd) return 0; } - //thd->infinidb_vtable.isInfiniDBDML = true; - THD::infinidb_state origState = thd->infinidb_vtable.vtable_state; //if (( (thd->lex)->sql_command == SQLCOM_UPDATE ) || ( (thd->lex)->sql_command == SQLCOM_UPDATE_MULTI ) ) { - gp_walk_info gwi; - thd->infinidb_vtable.vtable_state = THD::INFINIDB_CREATE_VTABLE; - gwi.thd = thd; //updateCP->subType (CalpontSelectExecutionPlan::SINGLEROW_SUBS); //set scalar updateCP->subType (CalpontSelectExecutionPlan::SELECT_SUBS); //@Bug 2975. @@ -1805,15 +1737,14 @@ uint32_t doUpdateDelete(THD* thd) gwi.clauseType = WHERE; - if (getSelectPlan(gwi, select_lex, updateCP) != 0) //@Bug 3030 Modify the error message for unsupported functions + if (getSelectPlan(gwi, select_lex, updateCP, false, true) != 0) //@Bug 3030 Modify the error message for unsupported functions { - if (thd->infinidb_vtable.isUpdateWithDerive) + if (gwi.cs_vtable_is_update_with_derive) { // @bug 4457. MySQL inconsistence! for some queries, some structures are only available // in the derived_tables_processing phase. So by pass the phase for DML only when the // execution plan can not be successfully generated. recover lex before returning; - thd->lex->select_lex.item_list = items; - thd->infinidb_vtable.vtable_state = origState; + thd->lex->first_select_lex()->item_list = items; return 0; } @@ -1963,7 +1894,7 @@ uint32_t doUpdateDelete(THD* thd) //cout<< "Plan is " << endl << *updateCP << endl; if (( (thd->lex)->sql_command == SQLCOM_UPDATE ) || ( (thd->lex)->sql_command == SQLCOM_UPDATE_MULTI ) ) - thd->lex->select_lex.item_list = items; + thd->lex->first_select_lex()->item_list = items; } //cout<< "Plan is " << endl << *updateCP << endl; @@ -1979,8 +1910,6 @@ uint32_t doUpdateDelete(THD* thd) boost::shared_ptr plan = pDMLPackage->get_ExecutionPlan(); updateCP->rmParms(ci->rmParms); updateCP->serialize(*plan); - // recover original vtable state - thd->infinidb_vtable.vtable_state = origState; //cout << "plan has bytes " << plan->length() << endl; pDMLPackage->write(bytestream); @@ -2350,6 +2279,9 @@ int ha_calpont_impl_rnd_init(TABLE* table) IDEBUG( cout << "rnd_init for table " << table->s->table_name.str << endl ); THD* thd = current_thd; + gp_walk_info gwi; + gwi.thd = thd; + //check whether the system is ready to process statement. #ifndef _MSC_VER static DBRM dbrm(true); @@ -2359,20 +2291,22 @@ int ha_calpont_impl_rnd_init(TABLE* table) { // Still not ready setError(thd, ER_INTERNAL_ERROR, "The system is not yet ready to accept queries"); - thd->infinidb_vtable.vtable_state = THD::INFINIDB_ERROR; return ER_INTERNAL_ERROR; } else if (bSystemQueryReady < 0) { // Still not ready setError(thd, ER_INTERNAL_ERROR, "DBRM is not responding. Cannot accept queries"); - thd->infinidb_vtable.vtable_state = THD::INFINIDB_ERROR; return ER_INTERNAL_ERROR; } - #endif - // prevent "create table as select" from running on slave - thd->infinidb_vtable.hasInfiniDBTable = true; + + // Set this to close all outstanding FEP connections on + // client disconnect in handlerton::closecon_handlerton(). + if ( !thd_get_ha_data(thd, mcs_hton)) + { + thd_set_ha_data(thd, mcs_hton, reinterpret_cast(0x42)); + } cal_connection_info* ci = reinterpret_cast(get_fe_conn_info_ptr()); @@ -2387,40 +2321,12 @@ int ha_calpont_impl_rnd_init(TABLE* table) thd->lex->sql_command == SQLCOM_LOAD)) return 0; - // @bug 3005. if the table is not $vtable, then this could be a UDF defined on the connector. - // watch this for other complications - if (thd->infinidb_vtable.vtable_state == THD::INFINIDB_SELECT_VTABLE && - string(table->s->table_name.str).find("$vtable") != 0) - return 0; - - // return error is error status is already set - if (thd->infinidb_vtable.vtable_state == THD::INFINIDB_ERROR) - return ER_INTERNAL_ERROR; - - // by pass the extra union trips. return 0 - if (thd->infinidb_vtable.isUnion && thd->infinidb_vtable.vtable_state == THD::INFINIDB_CREATE_VTABLE) - return 0; - - // @bug 2232. Basic SP support. Error out non support sp cases. - // @bug 3939. Only error out for sp with select. Let pass for alter table in sp. - if (thd->infinidb_vtable.call_sp && (thd->lex)->sql_command != SQLCOM_ALTER_TABLE) - { - setError(thd, ER_CHECK_NOT_IMPLEMENTED, "This stored procedure syntax is not supported by Columnstore in this version"); - thd->infinidb_vtable.vtable_state = THD::INFINIDB_ERROR; - return ER_INTERNAL_ERROR; - } - - // mysql reads table twice for order by - if (thd->infinidb_vtable.vtable_state == THD::INFINIDB_REDO_PHASE1 || - thd->infinidb_vtable.vtable_state == THD::INFINIDB_ORDER_BY) - return 0; - if ( (thd->lex)->sql_command == SQLCOM_ALTER_TABLE ) return 0; //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)) - return doUpdateDelete(thd); + return doUpdateDelete(thd, gwi); uint32_t sessionID = tid2sid(thd->thread_id); boost::shared_ptr csc = CalpontSystemCatalog::makeCalpontSystemCatalog(sessionID); @@ -2431,12 +2337,6 @@ int ha_calpont_impl_rnd_init(TABLE* table) idbassert(ci != 0); - // MySQL sometimes calls rnd_init multiple times, plan should only be - // generated and sent once. - if (thd->infinidb_vtable.vtable_state == THD::INFINIDB_CREATE_VTABLE && - !thd->infinidb_vtable.isNewQuery) - return 0; - if (thd->killed == KILL_QUERY || thd->killed == KILL_QUERY_HARD) { force_close_fep_conn(thd, ci); @@ -2448,24 +2348,12 @@ int ha_calpont_impl_rnd_init(TABLE* table) sm::cpsm_conhdl_t* hndl; SCSEP csep; - // update traceFlags according to the autoswitch state. replication query - // on slave are in table mode (create table as...) - if (thd->infinidb_vtable.vtable_state == THD::INFINIDB_DISABLE_VTABLE || - (thd->slave_thread && thd->infinidb_vtable.vtable_state == THD::INFINIDB_INIT)) - { - ci->traceFlags |= CalpontSelectExecutionPlan::TRACE_TUPLE_OFF; - thd->infinidb_vtable.vtable_state = THD::INFINIDB_DISABLE_VTABLE; - } - else - { - ci->traceFlags = (ci->traceFlags | CalpontSelectExecutionPlan::TRACE_TUPLE_OFF)^ - CalpontSelectExecutionPlan::TRACE_TUPLE_OFF; - } + // update traceFlags according to the autoswitch state. + ci->traceFlags |= CalpontSelectExecutionPlan::TRACE_TUPLE_OFF; bool localQuery = get_local_query(thd); // table mode - if (thd->infinidb_vtable.vtable_state == THD::INFINIDB_DISABLE_VTABLE) { ti = ci->tableMap[table]; @@ -2530,154 +2418,15 @@ int ha_calpont_impl_rnd_init(TABLE* table) // for ExeMgr logging sqltext. only log once for the query although multi plans may be sent if (ci->tableMap.size() == 1) + { ti.csep->data(idb_mysql_query_str(thd)); + } + else + { + ti.csep->data(""); + } } - // vtable mode - else - { - //if (!ci->cal_conn_hndl || thd->infinidb_vtable.vtable_state == THD::INFINIDB_CREATE_VTABLE) - if ( thd->infinidb_vtable.vtable_state == THD::INFINIDB_CREATE_VTABLE) - { - ci->stats.reset(); // reset query stats - ci->stats.setStartTime(); - if (thd->main_security_ctx.user) - { - ci->stats.fUser = thd->main_security_ctx.user; - } - else - { - ci->stats.fUser = ""; - } - if (thd->main_security_ctx.host) - ci->stats.fHost = thd->main_security_ctx.host; - else if (thd->main_security_ctx.host_or_ip) - ci->stats.fHost = thd->main_security_ctx.host_or_ip; - else - ci->stats.fHost = "unknown"; - - try - { - ci->stats.userPriority(ci->stats.fHost, ci->stats.fUser); - } - catch (std::exception& e) - { - string msg = string("Columnstore User Priority - ") + e.what(); - ci->warningMsg = msg; - } - - // if the previous query has error, re-establish the connection - if (ci->queryState != 0) - { - sm::sm_cleanup(ci->cal_conn_hndl); - ci->cal_conn_hndl = 0; - } - } - - sm::sm_init(sessionID, &ci->cal_conn_hndl, localQuery); - idbassert(ci->cal_conn_hndl != 0); - ci->cal_conn_hndl->csc = csc; - idbassert(ci->cal_conn_hndl->exeMgr != 0); - - try - { - ci->cal_conn_hndl->connect(); - } - catch (...) - { - setError(thd, ER_INTERNAL_ERROR, IDBErrorInfo::instance()->errorMsg(ERR_LOST_CONN_EXEMGR)); - CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); - goto error; - } - - hndl = ci->cal_conn_hndl; - - if (thd->infinidb_vtable.vtable_state != THD::INFINIDB_SELECT_VTABLE) - { - //CalpontSelectExecutionPlan csep; - if (!csep) - csep.reset(new CalpontSelectExecutionPlan()); - - SessionManager sm; - BRM::TxnID txnID; - txnID = sm.getTxnID(sessionID); - - if (!txnID.valid) - { - txnID.id = 0; - txnID.valid = true; - } - - QueryContext verID; - verID = sm.verID(); - - csep->txnID(txnID.id); - csep->verID(verID); - csep->sessionID(sessionID); - - if (thd->db.length) - csep->schemaName(thd->db.str); - - csep->traceFlags(ci->traceFlags); - - if (thd->infinidb_vtable.isInsertSelect) - csep->queryType(CalpontSelectExecutionPlan::INSERT_SELECT); - - //get plan - int status = cp_get_plan(thd, csep); - - //if (cp_get_plan(thd, csep) != 0) - if (status > 0) - goto internal_error; - else if (status < 0) - return 0; - - // @bug 2547. don't need to send the plan if it's impossible where for all unions. - if (thd->infinidb_vtable.impossibleWhereOnUnion) - return 0; - - string query; - query.assign(thd->infinidb_vtable.original_query.ptr(), - thd->infinidb_vtable.original_query.length()); - csep->data(query); - - try - { - csep->priority( ci->stats.userPriority(ci->stats.fHost, ci->stats.fUser)); - } - catch (std::exception& e) - { - string msg = string("Columnstore User Priority - ") + e.what(); - push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 9999, msg.c_str()); - } - -#ifdef PLAN_HEX_FILE - // plan serialization - string tmpDir = aTmpDir + "/li1-plan.hex"; - - ifstream ifs(tmpDir.c_str()); - ByteStream bs1; - ifs >> bs1; - ifs.close(); - csep->unserialize(bs1); -#endif - - if (ci->traceFlags & 1) - { - cerr << "---------------- EXECUTION PLAN ----------------" << endl; - cerr << *csep << endl ; - cerr << "-------------- EXECUTION PLAN END --------------\n" << endl; - } - else - { - IDEBUG( cout << "---------------- EXECUTION PLAN ----------------" << endl ); - IDEBUG( cerr << *csep << endl ); - IDEBUG( cout << "-------------- EXECUTION PLAN END --------------\n" << endl ); - } - } - }// end of execution plan generation - - if (thd->infinidb_vtable.vtable_state != THD::INFINIDB_SELECT_VTABLE) { ByteStream msg; ByteStream emsgBs; @@ -2752,14 +2501,7 @@ int ha_calpont_impl_rnd_init(TABLE* table) ci->rmParms.clear(); - if (thd->infinidb_vtable.vtable_state == THD::INFINIDB_DISABLE_VTABLE) - { - ci->tableMap[table] = ti; - } - else - { - ci->queryState = 1; - } + ci->tableMap[table] = ti; break; } @@ -2772,10 +2514,7 @@ int ha_calpont_impl_rnd_init(TABLE* table) idbassert(hndl != 0); hndl->csc = csc; - if (thd->infinidb_vtable.vtable_state == THD::INFINIDB_DISABLE_VTABLE) - ti.conn_hndl = hndl; - else - ci->cal_conn_hndl = hndl; + ti.conn_hndl = hndl; try { @@ -2793,92 +2532,81 @@ int ha_calpont_impl_rnd_init(TABLE* table) } } - // set query state to be in_process. Sometimes mysql calls rnd_init multiple - // times, this makes sure plan only being generated and sent once. It will be - // reset when query finishes in sm::end_query - thd->infinidb_vtable.isNewQuery = false; - // common path for both vtable select phase and table mode -- open scan handle ti = ci->tableMap[table]; ti.msTablePtr = table; - if ((thd->infinidb_vtable.vtable_state == THD::INFINIDB_SELECT_VTABLE) || - (thd->infinidb_vtable.vtable_state == THD::INFINIDB_DISABLE_VTABLE) || - (thd->infinidb_vtable.vtable_state == THD::INFINIDB_REDO_QUERY)) + if (ti.tpl_ctx == 0) { - if (ti.tpl_ctx == 0) + ti.tpl_ctx = new sm::cpsm_tplh_t(); + ti.tpl_scan_ctx = sm::sp_cpsm_tplsch_t(new sm::cpsm_tplsch_t()); + } + + // make sure rowgroup is null so the new meta data can be taken. This is for some case mysql + // call rnd_init for a table more than once. + ti.tpl_scan_ctx->rowGroup = NULL; + + try + { + tableid = execplan::IDB_VTABLE_ID; + } + catch (...) + { + string emsg = "No table ID found for table " + string(table->s->table_name.str); + setError(thd, ER_INTERNAL_ERROR, emsg); + CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); + goto internal_error; + } + + try + { + sm::tpl_open(tableid, ti.tpl_ctx, hndl); + sm::tpl_scan_open(tableid, ti.tpl_scan_ctx, hndl); + } + catch (std::exception& e) + { + string emsg = "table can not be opened: " + string(e.what()); + setError(thd, ER_INTERNAL_ERROR, emsg); + CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); + goto internal_error; + } + catch (...) + { + string emsg = "table can not be opened"; + setError(thd, ER_INTERNAL_ERROR, emsg); + CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); + goto internal_error; + } + + ti.tpl_scan_ctx->traceFlags = ci->traceFlags; + + if ((ti.tpl_scan_ctx->ctp).size() == 0) + { + uint32_t num_attr = table->s->fields; + + for (uint32_t i = 0; i < num_attr; i++) { - ti.tpl_ctx = new sm::cpsm_tplh_t(); - ti.tpl_scan_ctx = sm::sp_cpsm_tplsch_t(new sm::cpsm_tplsch_t()); + CalpontSystemCatalog::ColType ctype; + ti.tpl_scan_ctx->ctp.push_back(ctype); } - // make sure rowgroup is null so the new meta data can be taken. This is for some case mysql - // call rnd_init for a table more than once. - ti.tpl_scan_ctx->rowGroup = NULL; + // populate coltypes here for table mode because tableband gives treeoid for dictionary column + { + CalpontSystemCatalog::RIDList oidlist = csc->columnRIDs(make_table(table->s->db.str, table->s->table_name.str), true); - try - { - tableid = execplan::IDB_VTABLE_ID; - } - catch (...) - { - string emsg = "No table ID found for table " + string(table->s->table_name.str); - setError(thd, ER_INTERNAL_ERROR, emsg); - CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); - goto internal_error; - } - - try - { - sm::tpl_open(tableid, ti.tpl_ctx, hndl); - sm::tpl_scan_open(tableid, ti.tpl_scan_ctx, hndl); - } - catch (std::exception& e) - { - string emsg = "table can not be opened: " + string(e.what()); - setError(thd, ER_INTERNAL_ERROR, emsg); - CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); - goto internal_error; - } - catch (...) - { - string emsg = "table can not be opened"; - setError(thd, ER_INTERNAL_ERROR, emsg); - CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); - goto internal_error; - } - - ti.tpl_scan_ctx->traceFlags = ci->traceFlags; - - if ((ti.tpl_scan_ctx->ctp).size() == 0) - { - uint32_t num_attr = table->s->fields; - - for (uint32_t i = 0; i < num_attr; i++) + if (oidlist.size() != num_attr) { - CalpontSystemCatalog::ColType ctype; - ti.tpl_scan_ctx->ctp.push_back(ctype); + string emsg = "Size mismatch probably caused by front end out of sync"; + setError(thd, ER_INTERNAL_ERROR, emsg); + CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); + goto internal_error; } - // populate coltypes here for table mode because tableband gives treeoid for dictionary column - if (thd->infinidb_vtable.vtable_state == THD::INFINIDB_DISABLE_VTABLE) + for (unsigned int j = 0; j < oidlist.size(); j++) { - CalpontSystemCatalog::RIDList oidlist = csc->columnRIDs(make_table(table->s->db.str, table->s->table_name.str), true); - - if (oidlist.size() != num_attr) - { - string emsg = "Size mismatch probably caused by front end out of sync"; - setError(thd, ER_INTERNAL_ERROR, emsg); - CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); - goto internal_error; - } - - for (unsigned int j = 0; j < oidlist.size(); j++) - { - CalpontSystemCatalog::ColType ctype = csc->colType(oidlist[j].objnum); - ti.tpl_scan_ctx->ctp[ctype.colPosition] = ctype; - ti.tpl_scan_ctx->ctp[ctype.colPosition].colPosition = -1; - } + CalpontSystemCatalog::ColType ctype = csc->colType(oidlist[j].objnum); + ti.tpl_scan_ctx->ctp[ctype.colPosition] = ctype; + ti.tpl_scan_ctx->ctp[ctype.colPosition].colPosition = -1; } } } @@ -2887,14 +2615,14 @@ int ha_calpont_impl_rnd_init(TABLE* table) return 0; error: - + // CS doesn't need to close the actual sockets + // b/c it tries to reuse it running next query. if (ci->cal_conn_hndl) { sm::sm_cleanup(ci->cal_conn_hndl); ci->cal_conn_hndl = 0; } - // do we need to close all connection handle of the table map? return ER_INTERNAL_ERROR; internal_error: @@ -2925,30 +2653,14 @@ int ha_calpont_impl_rnd_next(uchar* buf, TABLE* table) thd->lex->sql_command == SQLCOM_LOAD)) return 0; - if (thd->infinidb_vtable.vtable_state == THD::INFINIDB_ERROR) - return ER_INTERNAL_ERROR; - - // @bug 3005 - if (thd->infinidb_vtable.vtable_state == THD::INFINIDB_SELECT_VTABLE && - string(table->s->table_name.str).find("$vtable") != 0) - return HA_ERR_END_OF_FILE; - 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)) return HA_ERR_END_OF_FILE; // @bug 2547 - if (thd->infinidb_vtable.impossibleWhereOnUnion) - return HA_ERR_END_OF_FILE; - - // @bug 2232. Basic SP support - // @bug 3939. Only error out for sp with select. Let pass for alter table in sp. - if (thd->infinidb_vtable.call_sp && (thd->lex)->sql_command != SQLCOM_ALTER_TABLE) - { - setError(thd, ER_CHECK_NOT_IMPLEMENTED, "This stored procedure syntax is not supported by Columnstore in this version"); - thd->infinidb_vtable.vtable_state = THD::INFINIDB_ERROR; - return ER_INTERNAL_ERROR; - } +// TODO MCOL-2178 This variable can never be true in the scope of this function +// if (MIGR::infinidb_vtable.impossibleWhereOnUnion) +// return HA_ERR_END_OF_FILE; if (get_fe_conn_info_ptr() == NULL) set_fe_conn_info_ptr((void*)new cal_connection_info()); @@ -3011,15 +2723,15 @@ int ha_calpont_impl_rnd_next(uchar* buf, TABLE* table) return rc; } -int ha_calpont_impl_rnd_end(TABLE* table) +int ha_calpont_impl_rnd_end(TABLE* table, bool is_pushdown_hand) { int rc = 0; THD* thd = current_thd; cal_connection_info* ci = NULL; bool replicationEnabled = false; - if (thd->infinidb_vtable.cal_conn_info) - ci = reinterpret_cast(thd->infinidb_vtable.cal_conn_info); + if (get_fe_conn_info_ptr() != NULL) + ci = reinterpret_cast(get_fe_conn_info_ptr()); if (ci && ci->replicationEnabled) { @@ -3037,19 +2749,17 @@ int ha_calpont_impl_rnd_end(TABLE* table) thd->lex->sql_command == SQLCOM_LOAD)) return 0; - thd->infinidb_vtable.isNewQuery = true; + + // WIP MCOL-2178 + // Workaround because CS doesn't reset isUnion in a normal way. +// TODO MCOL-2178 isUnion member only assigned, never used +// if (is_pushdown_hand) +// { +// MIGR::infinidb_vtable.isUnion = false; +// } if (get_fe_conn_info_ptr() != NULL) ci = reinterpret_cast(get_fe_conn_info_ptr()); - if (thd->infinidb_vtable.vtable_state == THD::INFINIDB_ORDER_BY ) - { - thd->infinidb_vtable.vtable_state = THD::INFINIDB_SELECT_VTABLE; // flip back to normal state - return rc; - } - -// if (thd->infinidb_vtable.vtable_state == THD::INFINIDB_REDO_PHASE1) -// return rc; - if ( (thd->lex)->sql_command == SQLCOM_ALTER_TABLE ) return rc; @@ -3088,7 +2798,7 @@ int ha_calpont_impl_rnd_end(TABLE* table) cal_table_info ti = ci->tableMap[table]; sm::cpsm_conhdl_t* hndl; - if (thd->infinidb_vtable.vtable_state == THD::INFINIDB_DISABLE_VTABLE) + if (!is_pushdown_hand) hndl = ti.conn_hndl; else hndl = ci->cal_conn_hndl; @@ -3111,10 +2821,13 @@ int ha_calpont_impl_rnd_end(TABLE* table) try { - sm::tpl_close(ti.tpl_ctx, &hndl, ci->stats); + { + bool ask_4_stats = (ci->traceFlags) ? true : false; + sm::tpl_close(ti.tpl_ctx, &hndl, ci->stats, ask_4_stats); + } // set conn hndl back. could be changed in tpl_close - if (thd->infinidb_vtable.vtable_state == THD::INFINIDB_DISABLE_VTABLE) + if (!is_pushdown_hand) ti.conn_hndl = hndl; else ci->cal_conn_hndl = hndl; @@ -3148,10 +2861,6 @@ int ha_calpont_impl_rnd_end(TABLE* table) ti.tpl_ctx = 0; - if (thd->infinidb_vtable.vtable_state == THD::INFINIDB_SELECT_VTABLE && - thd->infinidb_vtable.has_order_by) - thd->infinidb_vtable.vtable_state = THD::INFINIDB_ORDER_BY; - ci->tableMap[table] = ti; // push warnings from CREATE phase @@ -3162,6 +2871,8 @@ int ha_calpont_impl_rnd_end(TABLE* table) // reset expressionId just in case ci->expressionId = 0; + thd_set_ha_data(thd, mcs_hton, reinterpret_cast(ci)); + return rc; } @@ -3175,8 +2886,7 @@ int ha_calpont_impl_create(const char* name, TABLE* table_arg, HA_CREATE_INFO* c cal_connection_info* ci = reinterpret_cast(get_fe_conn_info_ptr()); // @bug1940 Do nothing for select query. Support of set default engine to IDB. - if (thd->infinidb_vtable.vtable_state == THD::INFINIDB_CREATE_VTABLE || - string(name).find("@0024vtable") != string::npos) + if (string(name).find("@0024vtable") != string::npos) return 0; //@Bug 1948. Mysql calls create table to create a new table with new signature. @@ -3235,7 +2945,7 @@ int ha_calpont_impl_delete_table(const char* name) } else { - TABLE_LIST* first_table = (TABLE_LIST*) thd->lex->select_lex.table_list.first; + TABLE_LIST* first_table = (TABLE_LIST*) thd->lex->first_select_lex()->table_list.first; dbName = const_cast(first_table->db.str); } @@ -3376,14 +3086,11 @@ void ha_calpont_impl_start_bulk_insert(ha_rows rows, TABLE* table) if (ci->alterTableState > 0) return; - if (thd->infinidb_vtable.vtable_state != THD::INFINIDB_ALTER_VTABLE) - thd->infinidb_vtable.isInfiniDBDML = true; - if (thd->slave_thread && !ci->replicationEnabled) return; //@bug 5660. Error out DDL/DML on slave node, or on local query node - if (ci->isSlaveNode && thd->infinidb_vtable.vtable_state != THD::INFINIDB_ALTER_VTABLE) + if (ci->isSlaveNode) { string emsg = logging::IDBErrorInfo::instance()->errorMsg(ERR_DML_DDL_SLAVE); setError(current_thd, ER_CHECK_NOT_IMPLEMENTED, emsg); @@ -4151,12 +3858,6 @@ int ha_calpont_impl_end_bulk_insert(bool abort, TABLE* table) int ha_calpont_impl_commit (handlerton* hton, THD* thd, bool all) { - if (thd->infinidb_vtable.vtable_state == THD::INFINIDB_CREATE_VTABLE || - thd->infinidb_vtable.vtable_state == THD::INFINIDB_ALTER_VTABLE || - thd->infinidb_vtable.vtable_state == THD::INFINIDB_DROP_VTABLE || - thd->infinidb_vtable.vtable_state == THD::INFINIDB_REDO_PHASE1) - return 0; - if (get_fe_conn_info_ptr() == NULL) set_fe_conn_info_ptr((void*)new cal_connection_info()); @@ -4189,15 +3890,6 @@ int ha_calpont_impl_commit (handlerton* hton, THD* thd, bool all) int ha_calpont_impl_rollback (handlerton* hton, THD* thd, bool all) { - // @bug 1738. no need to rollback for select. This is to avoid concurrent session - // conflict because DML is not thread safe. - //comment out for bug 3874. Select should never come to rollback. If there is no active transaction, - //rollback in DMLProc is not doing anything anyway - //if (!(current_thd->variables.option_bits & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) - //{ - // return 0; - //} - if (get_fe_conn_info_ptr() == NULL) set_fe_conn_info_ptr((void*)new cal_connection_info()); @@ -4207,7 +3899,6 @@ int ha_calpont_impl_rollback (handlerton* hton, THD* thd, bool all) { ci->dmlProc = new MessageQueueClient("DMLProc"); - //cout << "rollback starts a client " << ci->dmlProc << " for session " << thd->thread_id << endl; } int rc = ha_calpont_impl_rollback_(hton, thd, all, *ci); @@ -4234,7 +3925,7 @@ int ha_calpont_impl_close_connection (handlerton* hton, THD* thd) // An ugly way. I will use ha_data w/o external_lock. // This in MCOL-2178 cal_connection_info* ci = NULL; - if(thd_get_ha_data(thd, hton)) + if(thd_get_ha_data(thd, hton) != (void*)0x42) // 0x42 is the magic CS sets when setup hton { ci = reinterpret_cast(thd_get_ha_data(thd, hton)); } @@ -4256,13 +3947,14 @@ int ha_calpont_impl_close_connection (handlerton* hton, THD* thd) ci->cal_conn_hndl = 0; } + thd_set_ha_data(thd, hton, NULL); + return rc; } int ha_calpont_impl_rename_table(const char* from, const char* to) { IDEBUG( cout << "ha_calpont_impl_rename_table: " << from << " => " << to << endl ); - THD* thd = current_thd; if (get_fe_conn_info_ptr() == NULL) set_fe_conn_info_ptr((void*)new cal_connection_info()); @@ -4282,8 +3974,6 @@ int ha_calpont_impl_rename_table(const char* from, const char* to) IDEBUG( cout << "ha_calpont_impl_rename_table: was in state ALTER_SECOND_RENAME, now in NOT_ALTER" << endl ); return 0; } - else if ( thd->infinidb_vtable.vtable_state == THD::INFINIDB_ALTER_VTABLE ) - return 0; int rc = ha_calpont_impl_rename_table_(from, to, *ci); return rc; @@ -4299,12 +3989,6 @@ COND* ha_calpont_impl_cond_push(COND* cond, TABLE* table) { THD* thd = current_thd; - if (thd->slave_thread && thd->infinidb_vtable.vtable_state == THD::INFINIDB_INIT) - thd->infinidb_vtable.vtable_state = THD::INFINIDB_DISABLE_VTABLE; - - if (thd->infinidb_vtable.vtable_state != THD::INFINIDB_DISABLE_VTABLE) - return cond; - if (((thd->lex)->sql_command == SQLCOM_UPDATE) || ((thd->lex)->sql_command == SQLCOM_UPDATE_MULTI) || ((thd->lex)->sql_command == SQLCOM_DELETE) || @@ -4389,12 +4073,6 @@ int ha_calpont_impl_external_lock(THD* thd, TABLE* table, int lock_type) string alias; alias.assign(table->alias.ptr(), table->alias.length()); IDEBUG( cout << "external_lock for " << alias << endl ); - idbassert((thd->infinidb_vtable.vtable_state >= THD::INFINIDB_INIT_CONNECT && - thd->infinidb_vtable.vtable_state <= THD::INFINIDB_REDO_QUERY) || - thd->infinidb_vtable.vtable_state == THD::INFINIDB_ERROR); - - if ( thd->infinidb_vtable.vtable_state == THD::INFINIDB_INIT ) - return 0; if (get_fe_conn_info_ptr() == NULL) set_fe_conn_info_ptr((void*)new cal_connection_info()); @@ -4403,51 +4081,56 @@ int ha_calpont_impl_external_lock(THD* thd, TABLE* table, int lock_type) if (thd->killed == KILL_QUERY || thd->killed == KILL_QUERY_HARD) { + ci->physTablesList.clear(); + ci->tableMap.clear(); force_close_fep_conn(thd, ci); return 0; } - CalTableMap::iterator mapiter = ci->tableMap.find(table); -#ifdef _MSC_VER - //FIXME: fix this! (must be related to F_UNLCK define in winport) - if (mapiter != ci->tableMap.end() && lock_type == 0) // make sure it's the release lock (2nd) call -#else + CalTableMap::iterator mapiter = ci->tableMap.find(table); if (mapiter != ci->tableMap.end() && lock_type == 2) // make sure it's the release lock (2nd) call -#endif { // table mode - if (thd->infinidb_vtable.vtable_state == THD::INFINIDB_DISABLE_VTABLE) + if (mapiter->second.conn_hndl) { - if (mapiter->second.conn_hndl) - { - if (ci->traceFlags & 1) - push_warning(thd, Sql_condition::WARN_LEVEL_NOTE, 9999, mapiter->second.conn_hndl->queryStats.c_str()); + if (ci->traceFlags & 1) + push_warning(thd, Sql_condition::WARN_LEVEL_NOTE, 9999, mapiter->second.conn_hndl->queryStats.c_str()); - ci->queryStats = mapiter->second.conn_hndl->queryStats; - ci->extendedStats = mapiter->second.conn_hndl->extendedStats; - ci->miniStats = mapiter->second.conn_hndl->miniStats; - sm::sm_cleanup(mapiter->second.conn_hndl); - mapiter->second.conn_hndl = 0; - } - - if (mapiter->second.condInfo) - { - delete mapiter->second.condInfo; - mapiter->second.condInfo = 0; - } - - // only push this warning for once - if (ci->tableMap.size() == 1 && - thd->infinidb_vtable.vtable_state == THD::INFINIDB_DISABLE_VTABLE && thd->infinidb_vtable.autoswitch) - { - push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 9999, infinidb_autoswitch_warning.c_str()); - } - ci->queryState = 0; + ci->queryStats = mapiter->second.conn_hndl->queryStats; + ci->extendedStats = mapiter->second.conn_hndl->extendedStats; + ci->miniStats = mapiter->second.conn_hndl->miniStats; + sm::sm_cleanup(mapiter->second.conn_hndl); + mapiter->second.conn_hndl = 0; } - else // vtable mode + + if (mapiter->second.condInfo) { - if (thd->infinidb_vtable.vtable_state == THD::INFINIDB_SELECT_VTABLE) + delete mapiter->second.condInfo; + mapiter->second.condInfo = 0; + } + + // MCOL-2178 Check for tableMap size to set this only once. + ci->queryState = 0; + ci->tableMap.erase(table); + } + else + { + if (lock_type == 0) + { + ci->physTablesList.insert(table); + // MCOL-2178 Disable Conversion of Big IN Predicates Into Subqueries + thd->variables.in_subquery_conversion_threshold=~0; + } + else if (lock_type == 2) + { + std::set::iterator iter = ci->physTablesList.find(table); + if ( iter != ci->physTablesList.end() ) + { + ci->physTablesList.erase(table); + } + + if ( iter != ci->physTablesList.end() && ci->physTablesList.empty() ) { if (!ci->cal_conn_hndl) return 0; @@ -4459,14 +4142,16 @@ int ha_calpont_impl_external_lock(THD* thd, TABLE* table, int lock_type) ci->extendedStats = ci->cal_conn_hndl->extendedStats; ci->miniStats = ci->cal_conn_hndl->miniStats; ci->queryState = 0; - thd->infinidb_vtable.override_largeside_estimate = false; // MCOL-3247 Use THD::ha_data as a per-plugin per-session - // storage for cal_conn_hndl to use it later in close_connection - thd_set_ha_data(thd, calpont_hton, get_fe_conn_info_ptr()); + // storage for cal_conn_hndl to use it later in close_connection + thd_set_ha_data(thd, mcs_hton, get_fe_conn_info_ptr()); + ci->tableMap.clear(); + // MCOL-2178 Enable Conversion of Big IN Predicates Into Subqueries + thd->variables.in_subquery_conversion_threshold = IN_SUBQUERY_CONVERSION_THRESHOLD; + restore_optimizer_flags(thd); } - } - ci->tableMap.erase(table); + } } return 0; @@ -4508,38 +4193,16 @@ int ha_calpont_impl_group_by_init(ha_calpont_group_by_handler* group_hand, TABLE { // Still not ready setError(thd, ER_INTERNAL_ERROR, "The system is not yet ready to accept queries"); - thd->infinidb_vtable.vtable_state = THD::INFINIDB_ERROR; return ER_INTERNAL_ERROR; } else if (bSystemQueryReady < 0) { // Still not ready setError(thd, ER_INTERNAL_ERROR, "DBRM is not responding. Cannot accept queries"); - thd->infinidb_vtable.vtable_state = THD::INFINIDB_ERROR; return ER_INTERNAL_ERROR; } #endif - // prevent "create table as select" from running on slave - thd->infinidb_vtable.hasInfiniDBTable = true; - - // return error if error status has been already set - if (thd->infinidb_vtable.vtable_state == THD::INFINIDB_ERROR) - return ER_INTERNAL_ERROR; - - // MCOL-1052 - // by pass the extra union trips. return 0 - //if (thd->infinidb_vtable.isUnion && thd->infinidb_vtable.vtable_state == THD::INFINIDB_CREATE_VTABLE) - // return 0; - - // @bug 2232. Basic SP support. Error out non support sp cases. - // @bug 3939. Only error out for sp with select. Let pass for alter table in sp. - if (thd->infinidb_vtable.call_sp && (thd->lex)->sql_command != SQLCOM_ALTER_TABLE) - { - setError(thd, ER_CHECK_NOT_IMPLEMENTED, "This stored procedure syntax is not supported by Columnstore in this version"); - thd->infinidb_vtable.vtable_state = THD::INFINIDB_ERROR; - return ER_INTERNAL_ERROR; - } uint32_t sessionID = tid2sid(thd->thread_id); boost::shared_ptr csc = CalpontSystemCatalog::makeCalpontSystemCatalog(sessionID); @@ -4553,12 +4216,6 @@ int ha_calpont_impl_group_by_init(ha_calpont_group_by_handler* group_hand, TABLE idbassert(ci != 0); - // MySQL sometimes calls rnd_init multiple times, plan should only be - // generated and sent once. - if (thd->infinidb_vtable.vtable_state == THD::INFINIDB_DISABLE_VTABLE && - !thd->infinidb_vtable.isNewQuery) - return 0; - if (thd->killed == KILL_QUERY || thd->killed == KILL_QUERY_HARD) { force_close_fep_conn(thd, ci); @@ -4692,14 +4349,17 @@ int ha_calpont_impl_group_by_init(ha_calpont_group_by_handler* group_hand, TABLE // send plan whenever group_init is called int status = cp_get_group_plan(thd, csep, gi); + // WIP MCOL-2178 This could be a problem if (status > 0) goto internal_error; else if (status < 0) return 0; // @bug 2547. don't need to send the plan if it's impossible where for all unions. - if (thd->infinidb_vtable.impossibleWhereOnUnion) - return 0; +// TODO MCOL-2178 commenting the below out since cp_get_group_plan does not modify this variable +// which has a default value of false +// if (MIGR::infinidb_vtable.impossibleWhereOnUnion) +// return 0; string query; // Set the query text only once if the server executes @@ -4819,14 +4479,7 @@ int ha_calpont_impl_group_by_init(ha_calpont_group_by_handler* group_hand, TABLE ci->rmParms.clear(); - if (thd->infinidb_vtable.vtable_state == THD::INFINIDB_DISABLE_VTABLE) - { - ci->tableMap[table] = ti; - } - else - { - ci->queryState = 1; - } + ci->queryState = 1; break; } @@ -4839,15 +4492,9 @@ int ha_calpont_impl_group_by_init(ha_calpont_group_by_handler* group_hand, TABLE idbassert(hndl != 0); hndl->csc = csc; - // The next section is useless - if (thd->infinidb_vtable.vtable_state == THD::INFINIDB_DISABLE_VTABLE) - ti.conn_hndl = hndl; - else - { - ci->cal_conn_hndl = hndl; - ci->cal_conn_hndl_st.pop(); - ci->cal_conn_hndl_st.push(ci->cal_conn_hndl); - } + ci->cal_conn_hndl = hndl; + ci->cal_conn_hndl_st.pop(); + ci->cal_conn_hndl_st.push(ci->cal_conn_hndl); try { hndl->connect(); @@ -4867,18 +4514,11 @@ int ha_calpont_impl_group_by_init(ha_calpont_group_by_handler* group_hand, TABLE // set query state to be in_process. Sometimes mysql calls rnd_init multiple // times, this makes sure plan only being generated and sent once. It will be // reset when query finishes in sm::end_query - thd->infinidb_vtable.isNewQuery = false; // common path for both vtable select phase and table mode -- open scan handle ti = ci->tableMap[table]; ti.msTablePtr = table; - // MCOL-1052 - thd->infinidb_vtable.vtable_state = THD::INFINIDB_SELECT_VTABLE; - - if ((thd->infinidb_vtable.vtable_state == THD::INFINIDB_SELECT_VTABLE) || - (thd->infinidb_vtable.vtable_state == THD::INFINIDB_DISABLE_VTABLE) || - (thd->infinidb_vtable.vtable_state == THD::INFINIDB_REDO_QUERY)) { // MCOL-1601 Using stacks of ExeMgr conn hndls, table and scan contexts. ti.tpl_ctx = new sm::cpsm_tplh_t(); @@ -4933,27 +4573,6 @@ int ha_calpont_impl_group_by_init(ha_calpont_group_by_handler* group_hand, TABLE CalpontSystemCatalog::ColType ctype; ti.tpl_scan_ctx->ctp.push_back(ctype); } - - // populate coltypes here for table mode because tableband gives treeoid for dictionary column - if (thd->infinidb_vtable.vtable_state == THD::INFINIDB_DISABLE_VTABLE) - { - CalpontSystemCatalog::RIDList oidlist = csc->columnRIDs(make_table(table->s->db.str, table->s->table_name.str), true); - - if (oidlist.size() != num_attr) - { - string emsg = "Size mismatch probably caused by front end out of sync"; - setError(thd, ER_INTERNAL_ERROR, emsg); - CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); - goto internal_error; - } - - for (unsigned int j = 0; j < oidlist.size(); j++) - { - CalpontSystemCatalog::ColType ctype = csc->colType(oidlist[j].objnum); - ti.tpl_scan_ctx->ctp[ctype.colPosition] = ctype; - ti.tpl_scan_ctx->ctp[ctype.colPosition].colPosition = -1; - } - } } } @@ -5002,26 +4621,15 @@ int ha_calpont_impl_group_by_next(ha_calpont_group_by_handler* group_hand, TABLE { THD* thd = current_thd; - if (thd->infinidb_vtable.vtable_state == THD::INFINIDB_ERROR) - return ER_INTERNAL_ERROR; - 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)) return HA_ERR_END_OF_FILE; // @bug 2547 - if (thd->infinidb_vtable.impossibleWhereOnUnion) - return HA_ERR_END_OF_FILE; +// TODO MCOL-2178 +// if (MIGR::infinidb_vtable.impossibleWhereOnUnion) +// return HA_ERR_END_OF_FILE; - // @bug 2232. Basic SP support - // @bug 3939. Only error out for sp with select. Let pass for alter table in sp. - /*if (thd->infinidb_vtable.call_sp && (thd->lex)->sql_command != SQLCOM_ALTER_TABLE) - { - setError(thd, ER_CHECK_NOT_IMPLEMENTED, "This stored procedure syntax is not supported by Columnstore in this version"); - thd->infinidb_vtable.vtable_state = THD::INFINIDB_ERROR; - return ER_INTERNAL_ERROR; - } - */ if (get_fe_conn_info_ptr() == NULL) set_fe_conn_info_ptr((void*)new cal_connection_info()); @@ -5103,18 +4711,6 @@ int ha_calpont_impl_group_by_end(ha_calpont_group_by_handler* group_hand, TABLE* THD* thd = current_thd; cal_connection_info* ci = NULL; - thd->infinidb_vtable.isNewQuery = true; - thd->infinidb_vtable.isUnion = false; - - if (get_fe_conn_info_ptr() != NULL) - ci = reinterpret_cast(get_fe_conn_info_ptr()); - - if (!ci) - { - thd->infinidb_vtable.cal_conn_info = (void*)(new cal_connection_info()); - ci = reinterpret_cast(thd->infinidb_vtable.cal_conn_info); - } - if (thd->slave_thread && !ci->replicationEnabled && ( thd->lex->sql_command == SQLCOM_INSERT || thd->lex->sql_command == SQLCOM_INSERT_SELECT || @@ -5126,7 +4722,13 @@ int ha_calpont_impl_group_by_end(ha_calpont_group_by_handler* group_hand, TABLE* thd->lex->sql_command == SQLCOM_LOAD)) return 0; - if (((thd->lex)->sql_command == SQLCOM_INSERT) || +// TODO MCOL-2178 isUnion member only assigned, never used +// MIGR::infinidb_vtable.isUnion = false; + + if (get_fe_conn_info_ptr() != NULL) + ci = reinterpret_cast(get_fe_conn_info_ptr()); + + if (((thd->lex)->sql_command == SQLCOM_INSERT) || ((thd->lex)->sql_command == SQLCOM_INSERT_SELECT) ) { force_close_fep_conn(thd, ci, true); // with checking prev command rc @@ -5194,7 +4796,10 @@ int ha_calpont_impl_group_by_end(ha_calpont_group_by_handler* group_hand, TABLE* { if(hndl) { - sm::tpl_close(ti.tpl_ctx, &hndl, ci->stats, clearScanCtx); + { + bool ask_4_stats = (ci->traceFlags) ? true : false; + sm::tpl_close(ti.tpl_ctx, &hndl, ci->stats, ask_4_stats, clearScanCtx); + } // Normaly stats variables are set in external_lock method but we set it here // since they we pretend we are in vtable_disabled mode and the stats vars won't be set. // We sum the stats up here since server could run a number of @@ -5267,4 +4872,475 @@ int ha_calpont_impl_group_by_end(ha_calpont_group_by_handler* group_hand, TABLE* return rc; } + +/*@brief Initiate the query for derived_handler */ +/*********************************************************** + * DESCRIPTION: + * Execute the query and saves derived table query. + * There is an extra handler argument so I ended up with a + * new init function. The code is a copy of + * ha_calpont_impl_rnd_init() mostly. + * PARAMETERS: + * mcs_handler_info* pnt to an envelope struct + * TABLE* table - dest table to put the results into + * RETURN: + * rc as int + ***********************************************************/ +int ha_cs_impl_pushdown_init(mcs_handler_info* handler_info, TABLE* table) +{ +#ifdef DEBUG_SETENV + string home(getenv("HOME")); + + if (!getenv("CALPONT_HOME")) + { + string calpontHome(home + "/Calpont/etc/"); + setenv("CALPONT_HOME", calpontHome.c_str(), 1); + } + + if (!getenv("CALPONT_CONFIG_FILE")) + { + string calpontConfigFile(home + "/Calpont/etc/Columnstore.xml"); + setenv("CALPONT_CONFIG_FILE", calpontConfigFile.c_str(), 1); + } + + if (!getenv("CALPONT_CSC_IDENT")) + setenv("CALPONT_CSC_IDENT", "dm", 1); + +#endif + + IDEBUG( cout << "pushdown_init for table " << endl ); + THD* thd = current_thd; + + gp_walk_info gwi; + gwi.thd = thd; + + //check whether the system is ready to process statement. +#ifndef _MSC_VER + static DBRM dbrm(true); + int bSystemQueryReady = dbrm.getSystemQueryReady(); + + if (bSystemQueryReady == 0) + { + // Still not ready + setError(thd, ER_INTERNAL_ERROR, "The system is not yet ready to accept queries"); + return ER_INTERNAL_ERROR; + } + else if (bSystemQueryReady < 0) + { + // Still not ready + setError(thd, ER_INTERNAL_ERROR, "DBRM is not responding. Cannot accept queries"); + return ER_INTERNAL_ERROR; + } +#endif + + // Set this to close all outstanding FEP connections on + // client disconnect in handlerton::closecon_handlerton(). + if ( !thd_get_ha_data(thd, mcs_hton)) + { + thd_set_ha_data(thd, mcs_hton, reinterpret_cast(0x42)); + } + + if ( (thd->lex)->sql_command == SQLCOM_ALTER_TABLE ) + { + return 0; + } + + //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)) + return doUpdateDelete(thd, gwi); + + uint32_t sessionID = tid2sid(thd->thread_id); + boost::shared_ptr csc = CalpontSystemCatalog::makeCalpontSystemCatalog(sessionID); + csc->identity(CalpontSystemCatalog::FE); + + if (!get_fe_conn_info_ptr()) + set_fe_conn_info_ptr(reinterpret_cast(new cal_connection_info(), thd)); + + cal_connection_info* ci = reinterpret_cast(get_fe_conn_info_ptr()); + + idbassert(ci != 0); + + if (thd->killed == KILL_QUERY || thd->killed == KILL_QUERY_HARD) + { + if (ci->cal_conn_hndl) + { + // send ExeMgr a signal before closing the connection + ByteStream msg; + ByteStream::quadbyte qb = 0; + msg << qb; + + try + { + ci->cal_conn_hndl->exeMgr->write(msg); + } + catch (...) + { + // canceling query. ignore connection failure. + } + + sm::sm_cleanup(ci->cal_conn_hndl); + ci->cal_conn_hndl = 0; + } + + return 0; + } + + sm::tableid_t tableid = 0; + cal_table_info ti; + sm::cpsm_conhdl_t* hndl; + SCSEP csep; + // Declare handlers ptrs in this scope for future use. + select_handler* sh = NULL; + derived_handler* dh = NULL; + + // update traceFlags according to the autoswitch state. + ci->traceFlags = (ci->traceFlags | CalpontSelectExecutionPlan::TRACE_TUPLE_OFF)^ + CalpontSelectExecutionPlan::TRACE_TUPLE_OFF; + + bool localQuery = (get_local_query(thd) > 0 ? true : false); + + { + ci->stats.reset(); // reset query stats + ci->stats.setStartTime(); + ci->stats.fUser = thd->main_security_ctx.user; + + if (thd->main_security_ctx.host) + ci->stats.fHost = thd->main_security_ctx.host; + else if (thd->main_security_ctx.host_or_ip) + ci->stats.fHost = thd->main_security_ctx.host_or_ip; + else + ci->stats.fHost = "unknown"; + + try + { + ci->stats.userPriority(ci->stats.fHost, ci->stats.fUser); + } + catch (std::exception& e) + { + string msg = string("Columnstore User Priority - ") + e.what(); + ci->warningMsg = msg; + } + + // if the previous query has error, re-establish the connection + if (ci->queryState != 0) + { + sm::sm_cleanup(ci->cal_conn_hndl); + ci->cal_conn_hndl = 0; + } + + sm::sm_init(sessionID, &ci->cal_conn_hndl, localQuery); + idbassert(ci->cal_conn_hndl != 0); + ci->cal_conn_hndl->csc = csc; + idbassert(ci->cal_conn_hndl->exeMgr != 0); + + try + { + ci->cal_conn_hndl->connect(); + } + catch (...) + { + setError(thd, ER_INTERNAL_ERROR, IDBErrorInfo::instance()->errorMsg(ERR_LOST_CONN_EXEMGR)); + CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); + goto error; + } + + hndl = ci->cal_conn_hndl; + + // WIP MCOL-2178 + std::cout << idb_mysql_query_str(thd) << std::endl; + + { + if (!csep) + csep.reset(new CalpontSelectExecutionPlan()); + + SessionManager sm; + BRM::TxnID txnID; + txnID = sm.getTxnID(sessionID); + + if (!txnID.valid) + { + txnID.id = 0; + txnID.valid = true; + } + + QueryContext verID; + verID = sm.verID(); + + csep->txnID(txnID.id); + csep->verID(verID); + csep->sessionID(sessionID); + + if (thd->db.length) + csep->schemaName(thd->db.str); + + csep->traceFlags(ci->traceFlags); + + // cast the handler and get a plan. + int status = 42; + if (handler_info->hndl_type == mcs_handler_types_t::SELECT) + { + sh = reinterpret_cast(handler_info->hndl_ptr); + status = cs_get_select_plan(sh, thd, csep, gwi); + } + else if (handler_info->hndl_type == DERIVED) + { + dh = reinterpret_cast(handler_info->hndl_ptr); + status = cs_get_derived_plan(dh, thd, csep, gwi); + } + + // WIP MCOL-2178 Remove this + std::cout << "pushdown_init get_plan status " << status << std::endl; + + // Return an error to avoid MDB crash later in end_statement + if (status != 0) + goto internal_error; + + // WIP MCOL-2178 Remove this + std::cout << "pushdown_init impossibleWhereOnUnion " << status << std::endl; + // @bug 2547. don't need to send the plan if it's impossible where for all unions. + if (gwi.cs_vtable_impossible_where_on_union) + { + return 0; + } + + string query; + query.assign(idb_mysql_query_str(thd)); + csep->data(query); + + try + { + csep->priority( ci->stats.userPriority(ci->stats.fHost, ci->stats.fUser)); + } + catch (std::exception& e) + { + string msg = string("Columnstore User Priority - ") + e.what(); + push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 9999, msg.c_str()); + } + +#ifdef PLAN_HEX_FILE + // plan serialization + ifstream ifs("/tmp/li1-plan.hex"); + ByteStream bs1; + ifs >> bs1; + ifs.close(); + csep->unserialize(bs1); +#endif + + if (ci->traceFlags & 1) + { + cerr << "---------------- EXECUTION PLAN ----------------" << endl; + cerr << *csep << endl ; + cerr << "-------------- EXECUTION PLAN END --------------\n" << endl; + } + else + { + IDEBUG( cout << "---------------- EXECUTION PLAN ----------------" << endl ); + IDEBUG( cerr << *csep << endl ); + IDEBUG( cout << "-------------- EXECUTION PLAN END --------------\n" << endl ); + } + } + }// end of execution plan generation + + { + ByteStream msg; + ByteStream emsgBs; + + while (true) + { + try + { + ByteStream::quadbyte qb = 4; + msg << qb; + hndl->exeMgr->write(msg); + msg.restart(); + csep->rmParms(ci->rmParms); + + //send plan + csep->serialize(msg); + hndl->exeMgr->write(msg); + + //get ExeMgr status back to indicate a vtable joblist success or not + msg.restart(); + emsgBs.restart(); + msg = hndl->exeMgr->read(); + emsgBs = hndl->exeMgr->read(); + string emsg; + + if (msg.length() == 0 || emsgBs.length() == 0) + { + emsg = "Lost connection to ExeMgr. Please contact your administrator"; + setError(thd, ER_INTERNAL_ERROR, emsg); + return ER_INTERNAL_ERROR; + } + + string emsgStr; + emsgBs >> emsgStr; + bool err = false; + + if (msg.length() == 4) + { + msg >> qb; + + if (qb != 0) + { + err = true; + // for makejoblist error, stats contains only error code and insert from here + // because table fetch is not started + ci->stats.setEndTime(); + ci->stats.fQuery = csep->data(); + ci->stats.fQueryType = csep->queryType(); + ci->stats.fErrorNo = qb; + + try + { + ci->stats.insert(); + } + catch (std::exception& e) + { + string msg = string("Columnstore Query Stats - ") + e.what(); + push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 9999, msg.c_str()); + } + } + } + else + { + err = true; + } + + if (err) + { + setError(thd, ER_INTERNAL_ERROR, emsgStr); + return ER_INTERNAL_ERROR; + } + + ci->rmParms.clear(); + + ci->queryState = 1; + + break; + } + catch (...) + { + sm::sm_cleanup(hndl); + hndl = 0; + + sm::sm_init(sessionID, &hndl, localQuery); + idbassert(hndl != 0); + hndl->csc = csc; + + ci->cal_conn_hndl = hndl; + + try + { + hndl->connect(); + } + catch (...) + { + setError(thd, ER_INTERNAL_ERROR, IDBErrorInfo::instance()->errorMsg(ERR_LOST_CONN_EXEMGR)); + CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); + goto error; + } + + msg.restart(); + } + } + } + + // set query state to be in_process. Sometimes mysql calls rnd_init multiple + // times, this makes sure plan only being generated and sent once. It will be + // reset when query finishes in sm::end_query + + // common path for both vtable select phase and table mode -- open scan handle + ti = ci->tableMap[table]; + // This is the server's temp table for the result. + if(sh) + { + ti.msTablePtr = sh->table; + } + else + { + ti.msTablePtr = dh->table; + } + + { + if (ti.tpl_ctx == 0) + { + ti.tpl_ctx = new sm::cpsm_tplh_t(); + ti.tpl_scan_ctx = sm::sp_cpsm_tplsch_t(new sm::cpsm_tplsch_t()); + } + + // make sure rowgroup is null so the new meta data can be taken. This is for some case mysql + // call rnd_init for a table more than once. + ti.tpl_scan_ctx->rowGroup = NULL; + + try + { + tableid = execplan::IDB_VTABLE_ID; + } + catch (...) + { + string emsg = "No table ID found for table " + string(table->s->table_name.str); + setError(thd, ER_INTERNAL_ERROR, emsg); + CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); + goto internal_error; + } + + try + { + sm::tpl_open(tableid, ti.tpl_ctx, hndl); + sm::tpl_scan_open(tableid, ti.tpl_scan_ctx, hndl); + } + catch (std::exception& e) + { + string emsg = "table can not be opened: " + string(e.what()); + setError(thd, ER_INTERNAL_ERROR, emsg); + CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); + goto internal_error; + } + catch (...) + { + string emsg = "table can not be opened"; + setError(thd, ER_INTERNAL_ERROR, emsg); + CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); + goto internal_error; + } + + ti.tpl_scan_ctx->traceFlags = ci->traceFlags; + + if ((ti.tpl_scan_ctx->ctp).size() == 0) + { + uint32_t num_attr = table->s->fields; + + for (uint32_t i = 0; i < num_attr; i++) + { + CalpontSystemCatalog::ColType ctype; + ti.tpl_scan_ctx->ctp.push_back(ctype); + } + } + } + + ci->tableMap[table] = ti; + return 0; + +error: + + if (ci->cal_conn_hndl) + { + sm::sm_cleanup(ci->cal_conn_hndl); + ci->cal_conn_hndl = 0; + } + + // do we need to close all connection handle of the table map + return ER_INTERNAL_ERROR; + +internal_error: + + if (ci->cal_conn_hndl) + { + sm::sm_cleanup(ci->cal_conn_hndl); + ci->cal_conn_hndl = 0; + } + + return ER_INTERNAL_ERROR; +} // vim:sw=4 ts=4: diff --git a/dbcon/mysql/ha_calpont_impl.h b/dbcon/mysql/ha_calpont_impl.h index bdc0e0eef..7e8de5ce5 100644 --- a/dbcon/mysql/ha_calpont_impl.h +++ b/dbcon/mysql/ha_calpont_impl.h @@ -20,6 +20,7 @@ #define HA_CALPONT_IMPL_H__ #include "idb_mysql.h" +#include "ha_mcs_pushdown.h" #ifdef NEED_CALPONT_EXTERNS extern int ha_calpont_impl_discover_existence(const char* schema, const char* name); @@ -29,7 +30,7 @@ extern int ha_calpont_impl_open(const char* name, int mode, uint32_t test_if_loc extern int ha_calpont_impl_close(void); extern int ha_calpont_impl_rnd_init(TABLE* table); extern int ha_calpont_impl_rnd_next(uchar* buf, TABLE* table); -extern int ha_calpont_impl_rnd_end(TABLE* table); +extern int ha_calpont_impl_rnd_end(TABLE* table, bool is_derived_hand = false); extern int ha_calpont_impl_write_row(uchar* buf, TABLE* table); extern void ha_calpont_impl_start_bulk_insert(ha_rows rows, TABLE* table); extern int ha_calpont_impl_end_bulk_insert(bool abort, TABLE* table); @@ -45,6 +46,7 @@ extern int ha_calpont_impl_rnd_pos(uchar* buf, uchar* pos); extern int ha_calpont_impl_group_by_init(ha_calpont_group_by_handler* group_hand, TABLE* table); extern int ha_calpont_impl_group_by_next(ha_calpont_group_by_handler* group_hand, TABLE* table); extern int ha_calpont_impl_group_by_end(ha_calpont_group_by_handler* group_hand, TABLE* table); +extern int ha_cs_impl_pushdown_init(mcs_handler_info* handler_info , TABLE* table); #endif @@ -52,6 +54,7 @@ extern int ha_calpont_impl_group_by_end(ha_calpont_group_by_handler* group_hand, #include "ha_calpont_impl_if.h" #include "calpontsystemcatalog.h" #include "ha_calpont.h" +#include "ha_mcs_pushdown.h" extern int ha_calpont_impl_rename_table_(const char* from, const char* to, cal_impl_if::cal_connection_info& ci); extern int ha_calpont_impl_write_row_(uchar* buf, TABLE* table, cal_impl_if::cal_connection_info& ci, ha_rows& rowsInserted); extern int ha_calpont_impl_write_batch_row_(uchar* buf, TABLE* table, cal_impl_if::cal_connection_info& ci); @@ -71,6 +74,7 @@ extern std::string ha_calpont_impl_cleartablelock( cal_impl_if::cal_connection_ extern int ha_calpont_impl_group_by_init(ha_calpont_group_by_handler* group_hand, TABLE* table); extern int ha_calpont_impl_group_by_next(ha_calpont_group_by_handler* group_hand, TABLE* table); extern int ha_calpont_impl_group_by_end(ha_calpont_group_by_handler* group_hand, TABLE* table); +extern int ha_cs_impl_derived_next(TABLE* table); #endif #endif diff --git a/dbcon/mysql/ha_calpont_impl_if.h b/dbcon/mysql/ha_calpont_impl_if.h index 6d8945ad8..791aa999b 100644 --- a/dbcon/mysql/ha_calpont_impl_if.h +++ b/dbcon/mysql/ha_calpont_impl_if.h @@ -150,6 +150,8 @@ struct gp_walk_info // Kludge for MCOL-1472 bool inCaseStmt; + bool cs_vtable_is_update_with_derive; + bool cs_vtable_impossible_where_on_union; gp_walk_info() : sessionid(0), fatalParseError(false), @@ -166,8 +168,10 @@ struct gp_walk_info lastSub(0), derivedTbCnt(0), recursionLevel(-1), - recursionHWM(0), - inCaseStmt(false) + recursionHWM(0), + inCaseStmt(false), + cs_vtable_is_update_with_derive(false), + cs_vtable_impossible_where_on_union(false) {} ~gp_walk_info() {} @@ -286,6 +290,7 @@ struct cal_connection_info std::stack cal_conn_hndl_st; int queryState; CalTableMap tableMap; + std::set physTablesList; sm::tableid_t currentTable; uint32_t traceFlags; std::string queryStats; @@ -337,14 +342,16 @@ const std::string infinidb_err_msg = "\nThe query includes syntax that is not su int cp_get_plan(THD* thd, execplan::SCSEP& csep); int cp_get_table_plan(THD* thd, execplan::SCSEP& csep, cal_impl_if::cal_table_info& ti); int cp_get_group_plan(THD* thd, execplan::SCSEP& csep, cal_impl_if::cal_group_info& gi); -int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, execplan::SCSEP& csep, bool isUnion = false); +int cs_get_derived_plan(derived_handler* handler, THD* thd, execplan::SCSEP& csep, gp_walk_info& gwi); +int cs_get_select_plan(select_handler* handler, THD* thd, execplan::SCSEP& csep, gp_walk_info& gwi); +int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, execplan::SCSEP& csep, bool isUnion = false, bool isPushdownHand = false); int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, execplan::SCSEP& csep, cal_group_info& gi, bool isUnion = false); void setError(THD* thd, uint32_t errcode, const std::string errmsg, gp_walk_info* gwi); void setError(THD* thd, uint32_t errcode, const std::string errmsg); void gp_walk(const Item* item, void* arg); void parse_item (Item* item, std::vector& field_vec, bool& hasNonSupportItem, uint16& parseInfo, gp_walk_info* gwip = NULL); const std::string bestTableName(const Item_field* ifp); -bool isInfiniDB(TABLE* table_ptr); +bool isMCSTable(TABLE* table_ptr); // execution plan util functions prototypes execplan::ReturnedColumn* buildReturnedColumn(Item* item, gp_walk_info& gwi, bool& nonSupport, bool pushdownHand = false); diff --git a/dbcon/mysql/ha_from_sub.cpp b/dbcon/mysql/ha_from_sub.cpp index bcbfe5520..bf4901119 100644 --- a/dbcon/mysql/ha_from_sub.cpp +++ b/dbcon/mysql/ha_from_sub.cpp @@ -322,9 +322,12 @@ ParseTree* setDerivedFilter(THD* thd, ParseTree*& n, FromSubQuery::FromSubQuery(gp_walk_info& gwip) : SubQuery(gwip) {} -FromSubQuery::FromSubQuery(gp_walk_info& gwip, SELECT_LEX* sub) : - SubQuery(gwip), - fFromSub(sub) +FromSubQuery::FromSubQuery(gp_walk_info& gwip, + SELECT_LEX* sub, + bool isPushdownHandler) : + SubQuery(gwip), + fFromSub(sub), + fPushdownHand(isPushdownHandler) {} FromSubQuery::~FromSubQuery() @@ -346,7 +349,7 @@ SCSEP FromSubQuery::transform() csep->derivedTbAlias(fAlias); // always lower case csep->derivedTbView(fGwip.viewName.alias); - if (getSelectPlan(gwi, *fFromSub, csep) != 0) + if (getSelectPlan(gwi, *fFromSub, csep, fPushdownHand) != 0) { fGwip.fatalParseError = true; diff --git a/dbcon/mysql/ha_mcs_pushdown.cpp b/dbcon/mysql/ha_mcs_pushdown.cpp new file mode 100644 index 000000000..1b2981b84 --- /dev/null +++ b/dbcon/mysql/ha_mcs_pushdown.cpp @@ -0,0 +1,620 @@ +/* + Copyright (c) 2019 MariaDB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + + +// ha_calpont.cpp includes this file. + +void mutate_optimizer_flags(THD *thd_) +{ + // MCOL-2178 Disable all optimizer flags as it was in the fork. + // CS restores it later in SH::scan_end() and in case of an error + // in SH::scan_init() + set_original_optimizer_flags(thd_->variables.optimizer_switch, thd_); + thd_->variables.optimizer_switch = OPTIMIZER_SWITCH_IN_TO_EXISTS | + OPTIMIZER_SWITCH_EXISTS_TO_IN | + OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_DERIVED; +} + +void restore_optimizer_flags(THD *thd_) +{ + // MCOL-2178 restore original optimizer flags after SH, DH + ulonglong orig_flags = get_original_optimizer_flags(thd_); + if (orig_flags) + { + thd_->variables.optimizer_switch = orig_flags; + set_original_optimizer_flags(0, thd_); + } +} + + +/*@brief check_walk - It traverses filter conditions*/ +/************************************************************ + * DESCRIPTION: + * It traverses filter predicates looking for unsupported + * JOIN types: non-equi JOIN, e.g t1.c1 > t2.c2; + * logical OR. + * PARAMETERS: + * thd - THD pointer. + * derived - TABLE_LIST* to work with. + * RETURN: + * derived_handler if possible + * NULL in other case + ***********************************************************/ +void check_walk(const Item* item, void* arg) +{ + bool* unsupported_feature = static_cast(arg); + if ( *unsupported_feature ) + return; + switch (item->type()) + { + case Item::FUNC_ITEM: + { + const Item_func* ifp = static_cast(item); + + if ( ifp->functype() != Item_func::EQ_FUNC ) // NON-equi JOIN + { + if ( ifp->argument_count() == 2 && + ifp->arguments()[0]->type() == Item::FIELD_ITEM && + ifp->arguments()[1]->type() == Item::FIELD_ITEM ) + { + Item_field* left= static_cast(ifp->arguments()[0]); + Item_field* right= static_cast(ifp->arguments()[1]); + + if ( left->field->table != right->field->table ) + { + *unsupported_feature = true; + return; + } + } + else // IN + correlated subquery + { + if ( ifp->functype() == Item_func::NOT_FUNC + && ifp->arguments()[0]->type() == Item::EXPR_CACHE_ITEM ) + { + check_walk(ifp->arguments()[0], arg); + } + } + } + break; + } + + case Item::EXPR_CACHE_ITEM: // IN + correlated subquery + { + const Item_cache_wrapper* icw = static_cast(item); + if ( icw->get_orig_item()->type() == Item::FUNC_ITEM ) + { + const Item_func *ifp = static_cast(icw->get_orig_item()); + if ( ifp->argument_count() == 2 && + ( ifp->arguments()[0]->type() == Item::Item::SUBSELECT_ITEM + || ifp->arguments()[1]->type() == Item::Item::SUBSELECT_ITEM )) + { + *unsupported_feature = true; + return; + } + } + break; + } + + case Item::COND_ITEM: // OR in JOIN conds is unsupported yet + { + Item_cond* icp = (Item_cond*)item; + if ( is_cond_or(icp) ) + { + *unsupported_feature = true; + } + break; + } + default: + { + break; + } + } +} + +/*@brief create_calpont_group_by_handler- Creates handler*/ +/*********************************************************** + * DESCRIPTION: + * Creates a group_by pushdown handler if there is no: + * non-equi JOIN, e.g * t1.c1 > t2.c2 + * logical OR in the filter predicates + * Impossible WHERE + * Impossible HAVING + * and there is either GROUP BY or aggregation function + * exists at the top level. + * Valid queries with the last two crashes the server if + * processed. + * Details are in server/sql/group_by_handler.h + * PARAMETERS: + * thd - THD pointer + * query - Query structure LFM in group_by_handler.h + * RETURN: + * group_by_handler if success + * NULL in other case + ***********************************************************/ +static group_by_handler* +create_calpont_group_by_handler(THD* thd, Query* query) +{ + ha_calpont_group_by_handler* handler = NULL; + + // MCOL-2178 Disable SP support in the group_by_handler for now + // Check the session variable value to enable/disable use of + // group_by_handler + if (!get_group_by_handler(thd) || (thd->lex)->sphead) + { + return handler; + } + + // same as thd->lex->current_select + SELECT_LEX *select_lex = query->from->select_lex; + + // Create a handler if query is valid. See comments for details. + if ( query->group_by || select_lex->with_sum_func ) + { + bool unsupported_feature = false; + // revisit SELECT_LEX for all units + for(TABLE_LIST* tl = query->from; !unsupported_feature && tl; tl = tl->next_global) + { + select_lex = tl->select_lex; + // Correlation subquery. Comming soon so fail on this yet. + unsupported_feature = select_lex->is_correlated; + + // Impossible HAVING or WHERE + if ( ( !unsupported_feature && query->having && select_lex->having_value == Item::COND_FALSE ) + || ( select_lex->cond_count > 0 + && select_lex->cond_value == Item::COND_FALSE ) ) + { + unsupported_feature = true; + } + + // Unsupported JOIN conditions + if ( !unsupported_feature ) + { + JOIN *join = select_lex->join; + Item_cond *icp = 0; + + if (join != 0) + icp = reinterpret_cast(join->conds); + + if ( unsupported_feature == false + && icp ) + { + icp->traverse_cond(check_walk, &unsupported_feature, Item::POSTFIX); + } + + // Optimizer could move some join conditions into where + if (select_lex->where != 0) + icp = reinterpret_cast(select_lex->where); + + if ( unsupported_feature == false + && icp ) + { + icp->traverse_cond(check_walk, &unsupported_feature, Item::POSTFIX); + } + + } + } // unsupported features check ends here + + if ( !unsupported_feature ) + { + handler = new ha_calpont_group_by_handler(thd, query); + + // Notify the server, that CS handles GROUP BY, ORDER BY and HAVING clauses. + query->group_by = NULL; + query->order_by = NULL; + query->having = NULL; + } + } + + return handler; +} + +/*@brief create_columnstore_derived_handler- Creates handler*/ +/************************************************************ + * DESCRIPTION: + * Creates a derived handler if there is no non-equi JOIN, e.g + * t1.c1 > t2.c2 and logical OR in the filter predicates. + * More details in server/sql/derived_handler.h + * PARAMETERS: + * thd - THD pointer. + * derived - TABLE_LIST* to work with. + * RETURN: + * derived_handler if possible + * NULL in other case + ***********************************************************/ +static derived_handler* +create_columnstore_derived_handler(THD* thd, TABLE_LIST *derived) +{ + ha_columnstore_derived_handler* handler = NULL; + + // MCOL-2178 Disable SP support in the derived_handler for now + // Check the session variable value to enable/disable use of + // derived_handler + if (!get_derived_handler(thd) || (thd->lex)->sphead) + { + return handler; + } + + SELECT_LEX_UNIT *unit= derived->derived; + + bool unsupported_feature = false; + { + SELECT_LEX select_lex = *unit->first_select(); + JOIN* join = select_lex.join; + Item_cond* icp = 0; + + if (join != 0) + icp = reinterpret_cast(join->conds); + + if (!join) + { + icp = reinterpret_cast(select_lex.where); + } + + if ( icp ) + { + //icp->traverse_cond(check_walk, &unsupported_feature, Item::POSTFIX); + } + } + + if ( !unsupported_feature ) + handler= new ha_columnstore_derived_handler(thd, derived); + + return handler; +} + +/*********************************************************** + * DESCRIPTION: + * derived_handler constructor + * PARAMETERS: + * thd - THD pointer. + * tbl - tables involved. + ***********************************************************/ +ha_columnstore_derived_handler::ha_columnstore_derived_handler(THD *thd, + TABLE_LIST *dt) + : derived_handler(thd, calpont_hton) +{ + derived = dt; +} + +/*********************************************************** + * DESCRIPTION: + * derived_handler destructor + ***********************************************************/ +ha_columnstore_derived_handler::~ha_columnstore_derived_handler() +{} + +/*@brief Initiate the query for derived_handler */ +/*********************************************************** + * DESCRIPTION: + * Execute the query and saves derived table query. + * PARAMETERS: + * + * RETURN: + * rc as int + ***********************************************************/ +int ha_columnstore_derived_handler::init_scan() +{ + char query_buff[4096]; + + DBUG_ENTER("ha_columnstore_derived_handler::init_scan"); + + // Save query for logging + String derived_query(query_buff, sizeof(query_buff), thd->charset()); + derived_query.length(0); + derived->derived->print(&derived_query, QT_ORDINARY); + + mcs_handler_info mhi = mcs_handler_info(static_cast(this), DERIVED); + // this::table is the place for the result set + int rc = ha_cs_impl_pushdown_init(&mhi, table); + + DBUG_RETURN(rc); +} + +/*@brief Fetch next row for derived_handler */ +/*********************************************************** + * DESCRIPTION: + * Fetches next row and saves it in the temp table + * PARAMETERS: + * + * RETURN: + * rc as int + * + ***********************************************************/ +int ha_columnstore_derived_handler::next_row() +{ + DBUG_ENTER("ha_columnstore_derived_handler::next_row"); + + int rc = ha_calpont_impl_rnd_next(table->record[0], table); + + DBUG_RETURN(rc); +} + +/*@brief Finishes the scan and clean it up */ +/*********************************************************** + * DESCRIPTION: + * Finishes the scan for derived handler + * PARAMETERS: + * + * RETURN: + * rc as int + * + ***********************************************************/ +int ha_columnstore_derived_handler::end_scan() +{ + DBUG_ENTER("ha_columnstore_derived_handler::end_scan"); + + int rc = ha_calpont_impl_rnd_end(table, true); + + DBUG_RETURN(rc); +} + +void ha_columnstore_derived_handler::print_error(int, unsigned long) +{ +} + +/*********************************************************** + * DESCRIPTION: + * GROUP BY handler constructor + * PARAMETERS: + * thd - THD pointer. + * query - Query describing structure + ***********************************************************/ +ha_calpont_group_by_handler::ha_calpont_group_by_handler(THD* thd_arg, Query* query) + : group_by_handler(thd_arg, calpont_hton), + select(query->select), + table_list(query->from), + distinct(query->distinct), + where(query->where), + group_by(query->group_by), + order_by(query->order_by), + having(query->having) +{ +} + +/*********************************************************** + * DESCRIPTION: + * GROUP BY destructor + ***********************************************************/ +ha_calpont_group_by_handler::~ha_calpont_group_by_handler() +{ +} + +/*********************************************************** + * DESCRIPTION: + * Makes the plan and prepares the data + * RETURN: + * int rc + ***********************************************************/ +int ha_calpont_group_by_handler::init_scan() +{ + DBUG_ENTER("ha_calpont_group_by_handler::init_scan"); + + int rc = ha_calpont_impl_group_by_init(this, table); + + DBUG_RETURN(rc); +} + +/*********************************************************** + * DESCRIPTION: + * Fetches a row and saves it to a temporary table. + * RETURN: + * int rc + ***********************************************************/ +int ha_calpont_group_by_handler::next_row() +{ + DBUG_ENTER("ha_calpont_group_by_handler::next_row"); + int rc = ha_calpont_impl_group_by_next(this, table); + + DBUG_RETURN(rc); +} + +/*********************************************************** + * DESCRIPTION: + * Shuts the scan down. + * RETURN: + * int rc + ***********************************************************/ +int ha_calpont_group_by_handler::end_scan() +{ + DBUG_ENTER("ha_calpont_group_by_handler::end_scan"); + + int rc = ha_calpont_impl_group_by_end(this, table); + + DBUG_RETURN(rc); +} + +/*@brief create_columnstore_select_handler- Creates handler*/ +/************************************************************ + * DESCRIPTION: + * Creates a select handler if there is no non-equi JOIN, e.g + * t1.c1 > t2.c2 and logical OR in the filter predicates. + * More details in server/sql/select_handler.h + * PARAMETERS: + * thd - THD pointer. + * sel - SELECT_LEX* that describes the query. + * RETURN: + * select_handler if possible + * NULL in other case + ***********************************************************/ +static select_handler* +create_columnstore_select_handler(THD* thd, SELECT_LEX* select_lex) +{ + ha_columnstore_select_handler* handler = NULL; + + // MCOL-2178 Disable SP support in the select_handler for now. + // Check the session variable value to enable/disable use of + // select_handler + if (!get_select_handler(thd) || (thd->lex)->sphead) + { + return handler; + } + + bool unsupported_feature = false; + // Select_handler use the short-cut that effectively disables + // INSERT..SELECT and LDI + if ( (thd->lex)->sql_command == SQLCOM_INSERT_SELECT + || (thd->lex)->sql_command == SQLCOM_CREATE_TABLE ) + + { + unsupported_feature = true; + } + + // Impossible HAVING or WHERE + // WIP replace with function call + if ( unsupported_feature + || ( select_lex->having && select_lex->having_value == Item::COND_FALSE ) + || ( select_lex->cond_count > 0 + && select_lex->cond_value == Item::COND_FALSE ) ) + { + unsupported_feature = true; + } + + // Unsupported query check. + if ( !unsupported_feature ) + { + // JOIN expression from WHERE, ON expressions + JOIN* join = select_lex->join; + Item_cond* where_icp = 0; + Item_cond* on_icp = 0; + + if (join != 0) + { + where_icp = reinterpret_cast(join->conds); + } + + if ( where_icp ) + { + //where_icp->traverse_cond(check_walk, &unsupported_feature, Item::POSTFIX); + } + + // Looking for JOIN with ON expression through + // TABLE_LIST in FROM until CS meets unsupported feature + TABLE_LIST* table_ptr = select_lex->get_table_list(); + for (; !unsupported_feature && table_ptr; table_ptr = table_ptr->next_global) + { + if(table_ptr->on_expr) + { + on_icp = reinterpret_cast(table_ptr->on_expr); + //on_icp->traverse_cond(check_walk, &unsupported_feature, Item::POSTFIX); + } + } + + // CROSS JOIN w/o conditions isn't supported until MCOL-301 + // is ready. + if (join && join->table_count >= 2 && ( !where_icp && !on_icp )) + { + unsupported_feature = true; + } + } + + if (!unsupported_feature) + { + handler = new ha_columnstore_select_handler(thd, select_lex); + mutate_optimizer_flags(thd); + } + + return handler; +} + +/*********************************************************** + * DESCRIPTION: + * select_handler constructor + * PARAMETERS: + * thd - THD pointer. + * select_lex - sematic tree for the query. + ***********************************************************/ +ha_columnstore_select_handler::ha_columnstore_select_handler(THD *thd, + SELECT_LEX* select_lex) + : select_handler(thd, calpont_hton) +{ + select = select_lex; +} + +/*********************************************************** + * DESCRIPTION: + * select_handler constructor + ***********************************************************/ +ha_columnstore_select_handler::~ha_columnstore_select_handler() +{ +} + +/*@brief Initiate the query for select_handler */ +/*********************************************************** + * DESCRIPTION: + * Execute the query and saves select table query. + * PARAMETERS: + * + * RETURN: + * rc as int + ***********************************************************/ +int ha_columnstore_select_handler::init_scan() +{ + char query_buff[4096]; + + DBUG_ENTER("ha_columnstore_select_handler::init_scan"); + + // Save query for logging + String select_query(query_buff, sizeof(query_buff), thd->charset()); + select_query.length(0); + select->print(thd, &select_query, QT_ORDINARY); + + mcs_handler_info mhi = mcs_handler_info(static_cast(this), SELECT); + // this::table is the place for the result set + int rc = ha_cs_impl_pushdown_init(&mhi, table); + + DBUG_RETURN(rc); +} + +/*@brief Fetch next row for select_handler */ +/*********************************************************** + * DESCRIPTION: + * Fetches next row and saves it in the temp table + * PARAMETERS: + * + * RETURN: + * rc as int + * + ***********************************************************/ +int ha_columnstore_select_handler::next_row() +{ + DBUG_ENTER("ha_columnstore_select_handler::next_row"); + + int rc = ha_calpont_impl_rnd_next(table->record[0], table); + + DBUG_RETURN(rc); +} + +/*@brief Finishes the scan and clean it up */ +/*********************************************************** + * DESCRIPTION: + * Finishes the scan for select handler + * PARAMETERS: + * + * RETURN: + * rc as int + * + ***********************************************************/ +int ha_columnstore_select_handler::end_scan() +{ + DBUG_ENTER("ha_columnstore_select_handler::end_scan"); + + int rc = ha_calpont_impl_rnd_end(table, true); + + DBUG_RETURN(rc); +} + +void ha_columnstore_select_handler::print_error(int, unsigned long) +{} diff --git a/dbcon/mysql/ha_mcs_pushdown.h b/dbcon/mysql/ha_mcs_pushdown.h new file mode 100644 index 000000000..1012cfa8c --- /dev/null +++ b/dbcon/mysql/ha_mcs_pushdown.h @@ -0,0 +1,145 @@ +/* + Copyright (c) 2019 MariaDB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + + +#ifndef HA_MCS_PUSH +#define HA_MCS_PUSH + +#include "idb_mysql.h" +#include "ha_calpont.h" + +void mutate_optimizer_flags(THD *thd_); +void restore_optimizer_flags(THD *thd_); + +enum mcs_handler_types_t +{ + SELECT, + DERIVED, + GROUP_BY, + LEGACY +}; + +struct mcs_handler_info +{ + mcs_handler_info() : hndl_ptr(NULL), hndl_type(LEGACY) { }; + mcs_handler_info(mcs_handler_types_t type) : hndl_ptr(NULL), hndl_type(type) { }; + mcs_handler_info(void* ptr, mcs_handler_types_t type) : hndl_ptr(ptr), hndl_type(type) { }; + ~mcs_handler_info() { }; + void* hndl_ptr; + mcs_handler_types_t hndl_type; +}; + +/*@brief group_by_handler class*/ +/*********************************************************** + * DESCRIPTION: + * Provides server with group_by_handler API methods. + * One should read comments in server/sql/group_by_handler.h + * Attributes: + * select - attribute contains all GROUP BY, HAVING, ORDER items and calls it + * an extended SELECT list according to comments in + * server/sql/group_handler.cc. + * So the temporary table for + * select count(*) from b group by a having a > 3 order by a + * will have 4 columns not 1. + * However server ignores all NULLs used in + * GROUP BY, HAVING, ORDER. + * select_list_descr - contains Item description returned by Item->print() + * that is used in lookup for corresponding columns in + * extended SELECT list. + * table_list - contains all tables involved. Must be CS tables only. + * distinct - looks like a useless thing for now. Couldn't get it set by server. + * where - where items. + * group_by - group by ORDER items. + * order_by - order by ORDER items. + * having - having Item. + * Methods: + * init_scan - get plan and send it to ExeMgr. Get the execution result. + * next_row - get a row back from sm. + * end_scan - finish and clean the things up. + ***********************************************************/ +class ha_calpont_group_by_handler: public group_by_handler +{ +public: + ha_calpont_group_by_handler(THD* thd_arg, Query* query); + ~ha_calpont_group_by_handler(); + int init_scan(); + int next_row(); + int end_scan(); + + List* select; + TABLE_LIST* table_list; + bool distinct; + Item* where; + ORDER* group_by; + ORDER* order_by; + Item* having; +}; + +/*@brief derived_handler class*/ +/*********************************************************** + * DESCRIPTION: + * derived_handler API methods. Could be used by the server + * tp process sub-queries. + * More details in server/sql/dervied_handler.h + * INFINIDB_SHARE* hton share + * tbl in the constructor is the list of the tables involved. + * Methods: + * init_scan - get plan and send it to ExeMgr. Get the execution result. + * next_row - get a row back from sm. + * end_scan - finish and clean the things up. + ***********************************************************/ +class ha_columnstore_derived_handler: public derived_handler +{ +private: + INFINIDB_SHARE *share; + +public: + ha_columnstore_derived_handler(THD* thd_arg, TABLE_LIST *tbl); + ~ha_columnstore_derived_handler(); + int init_scan(); + int next_row(); + int end_scan(); + void print_error(int, unsigned long); +}; + +/*@brief select_handler class*/ +/*********************************************************** + * DESCRIPTION: + * select_handler API methods. Could be used by the server + * tp pushdown the whole query described by SELECT_LEX. + * More details in server/sql/select_handler.h + * INFINIDB_SHARE* hton share + * sel in the constructor is the semantic tree for the query. + * Methods: + * init_scan - get plan and send it to ExeMgr. Get the execution result. + * next_row - get a row back from sm. + * end_scan - finish and clean the things up. + ***********************************************************/ +class ha_columnstore_select_handler: public select_handler +{ +private: + INFINIDB_SHARE *share; + +public: + ha_columnstore_select_handler(THD* thd_arg, SELECT_LEX* sel); + ~ha_columnstore_select_handler(); + int init_scan(); + int next_row(); + int end_scan(); + void print_error(int, unsigned long); +}; + +#endif diff --git a/dbcon/mysql/ha_mcs_sysvars.cpp b/dbcon/mysql/ha_mcs_sysvars.cpp index ff6943fa4..2dfadcb6a 100644 --- a/dbcon/mysql/ha_mcs_sysvars.cpp +++ b/dbcon/mysql/ha_mcs_sysvars.cpp @@ -58,6 +58,48 @@ static MYSQL_THDVAR_ULONGLONG( 1 ); +// optimizer flags vault +static MYSQL_THDVAR_ULONGLONG( + original_optimizer_flags, + PLUGIN_VAR_NOSYSVAR | PLUGIN_VAR_NOCMDOPT, + "Vault for original optimizer flags. For internal usage.", + NULL, + NULL, + 0, + 0, + ~0U, + 1 +); + +static MYSQL_THDVAR_BOOL( + select_handler, + PLUGIN_VAR_NOCMDARG, + "Enable/Disable the MCS select_handler", + NULL, + NULL, + 1 +); + +static MYSQL_THDVAR_BOOL( + derived_handler, + PLUGIN_VAR_NOCMDARG, + "Enable/Disable the MCS derived_handler", + NULL, + NULL, + 1 +); + +static MYSQL_THDVAR_BOOL( + group_by_handler, + PLUGIN_VAR_NOCMDARG, + "Enable/Disable the MCS group_by_handler", + NULL, + NULL, + 1 +); + + + // legacy system variables static MYSQL_THDVAR_ULONG( decimal_scale, @@ -240,6 +282,10 @@ st_mysql_sys_var* mcs_system_variables[] = { MYSQL_SYSVAR(compression_type), MYSQL_SYSVAR(fe_conn_info_ptr), + MYSQL_SYSVAR(original_optimizer_flags), + MYSQL_SYSVAR(select_handler), + MYSQL_SYSVAR(derived_handler), + MYSQL_SYSVAR(group_by_handler), MYSQL_SYSVAR(decimal_scale), MYSQL_SYSVAR(use_decimal_scale), MYSQL_SYSVAR(ordered_only), @@ -275,14 +321,47 @@ void set_fe_conn_info_ptr(void* ptr, THD* thd) THDVAR(current_thd, fe_conn_info_ptr) = (uint64_t)(ptr); } -bool get_use_legacy_sysvars(THD* thd) +ulonglong get_original_optimizer_flags(THD* thd) { - return ( thd == NULL ) ? false : THDVAR(thd, use_legacy_sysvars); + return ( current_thd == NULL && thd == NULL ) ? NULL : + THDVAR(current_thd, original_optimizer_flags); } -void set_use_legacy_sysvars(THD* thd, bool value) +void set_original_optimizer_flags(ulonglong ptr, THD* thd) { - THDVAR(thd, use_legacy_sysvars) = value; + if ( current_thd == NULL && thd == NULL) + { + return; + } + + THDVAR(current_thd, original_optimizer_flags) = (uint64_t)(ptr); +} + +bool get_select_handler(THD* thd) +{ + return ( thd == NULL ) ? false : THDVAR(thd, select_handler); +} +void set_select_handler(THD* thd, bool value) +{ + THDVAR(thd, select_handler) = value; +} + +bool get_derived_handler(THD* thd) +{ + return ( thd == NULL ) ? false : THDVAR(thd, derived_handler); +} +void set_derived_handler(THD* thd, bool value) +{ + THDVAR(thd, derived_handler) = value; +} + +bool get_group_by_handler(THD* thd) +{ + return ( thd == NULL ) ? false : THDVAR(thd, group_by_handler); +} +void set_group_by_handler(THD* thd, bool value) +{ + THDVAR(thd, group_by_handler) = value; } void set_compression_type(THD* thd, ulong value) @@ -296,225 +375,135 @@ mcs_compression_type_t get_compression_type(THD* thd) { bool get_use_decimal_scale(THD* thd) { - if(get_use_legacy_sysvars(thd)) - return ( thd == NULL ) ? false : thd->variables.infinidb_use_decimal_scale; - else - return ( thd == NULL ) ? false : THDVAR(thd, use_decimal_scale); + return ( thd == NULL ) ? false : THDVAR(thd, use_decimal_scale); } void set_use_decimal_scale(THD* thd, bool value) { - if(get_use_legacy_sysvars(thd)) - thd->variables.infinidb_use_decimal_scale = value; - else - THDVAR(thd, use_decimal_scale) = value; + THDVAR(thd, use_decimal_scale) = value; } ulong get_decimal_scale(THD* thd) { - if(get_use_legacy_sysvars(thd)) - return ( thd == NULL ) ? 0 : thd->variables.infinidb_decimal_scale; - else - return ( thd == NULL ) ? 0 : THDVAR(thd, decimal_scale); + return ( thd == NULL ) ? 0 : THDVAR(thd, decimal_scale); } void set_decimal_scale(THD* thd, ulong value) { - if(get_use_legacy_sysvars(thd)) - thd->variables.infinidb_decimal_scale = value; - else - THDVAR(thd, decimal_scale) = value; + THDVAR(thd, decimal_scale) = value; } bool get_ordered_only(THD* thd) { - if(get_use_legacy_sysvars(thd)) - return ( thd == NULL ) ? false : thd->variables.infinidb_ordered_only; - else - return ( thd == NULL ) ? false : THDVAR(thd, ordered_only); + return ( thd == NULL ) ? false : THDVAR(thd, ordered_only); } void set_ordered_only(THD* thd, bool value) { - if(get_use_legacy_sysvars(thd)) - thd->variables.infinidb_ordered_only = value; - else - THDVAR(thd, ordered_only) = value; + THDVAR(thd, ordered_only) = value; } ulong get_string_scan_threshold(THD* thd) { - if(get_use_legacy_sysvars(thd)) - return ( thd == NULL ) ? 0 : thd->variables.infinidb_string_scan_threshold; - else - return ( thd == NULL ) ? 0 : THDVAR(thd, string_scan_threshold); + return ( thd == NULL ) ? 0 : THDVAR(thd, string_scan_threshold); } void set_string_scan_threshold(THD* thd, ulong value) { - if(get_use_legacy_sysvars(thd)) - thd->variables.infinidb_string_scan_threshold = value; - else - THDVAR(thd, string_scan_threshold) = value; + THDVAR(thd, string_scan_threshold) = value; } ulong get_stringtable_threshold(THD* thd) { - if(get_use_legacy_sysvars(thd)) - return ( thd == NULL ) ? 0 : thd->variables.infinidb_stringtable_threshold; - else - return ( thd == NULL ) ? 0 : THDVAR(thd, stringtable_threshold); + return ( thd == NULL ) ? 0 : THDVAR(thd, stringtable_threshold); } void set_stringtable_threshold(THD* thd, ulong value) { - if(get_use_legacy_sysvars(thd)) - thd->variables.infinidb_stringtable_threshold = value; - else - THDVAR(thd, stringtable_threshold) = value; + THDVAR(thd, stringtable_threshold) = value; } ulong get_diskjoin_smallsidelimit(THD* thd) { - if(get_use_legacy_sysvars(thd)) - return ( thd == NULL ) ? 0 : thd->variables.infinidb_diskjoin_smallsidelimit; - else - return ( thd == NULL ) ? 0 : THDVAR(thd, diskjoin_smallsidelimit); + return ( thd == NULL ) ? 0 : THDVAR(thd, diskjoin_smallsidelimit); } void set_diskjoin_smallsidelimit(THD* thd, ulong value) { - if(get_use_legacy_sysvars(thd)) - thd->variables.infinidb_diskjoin_smallsidelimit = value; - else - THDVAR(thd, diskjoin_smallsidelimit) = value; + THDVAR(thd, diskjoin_smallsidelimit) = value; } ulong get_diskjoin_largesidelimit(THD* thd) { - if(get_use_legacy_sysvars(thd)) - return ( thd == NULL ) ? 0 : thd->variables.infinidb_diskjoin_largesidelimit; - else - return ( thd == NULL ) ? 0 : THDVAR(thd, diskjoin_largesidelimit); + return ( thd == NULL ) ? 0 : THDVAR(thd, diskjoin_largesidelimit); } void set_diskjoin_largesidelimit(THD* thd, ulong value) { - if(get_use_legacy_sysvars(thd)) - thd->variables.infinidb_diskjoin_largesidelimit = value; - else - THDVAR(thd, diskjoin_largesidelimit) = value; + THDVAR(thd, diskjoin_largesidelimit) = value; } ulong get_diskjoin_bucketsize(THD* thd) { - if(get_use_legacy_sysvars(thd)) - return ( thd == NULL ) ? 0 : thd->variables.infinidb_diskjoin_bucketsize; - else - return ( thd == NULL ) ? 0 : THDVAR(thd, diskjoin_bucketsize); + return ( thd == NULL ) ? 0 : THDVAR(thd, diskjoin_bucketsize); } void set_diskjoin_bucketsize(THD* thd, ulong value) { - if(get_use_legacy_sysvars(thd)) - thd->variables.infinidb_diskjoin_bucketsize = value; - else - THDVAR(thd, diskjoin_bucketsize) = value; + THDVAR(thd, diskjoin_bucketsize) = value; } ulong get_um_mem_limit(THD* thd) { - if(get_use_legacy_sysvars(thd)) - return ( thd == NULL ) ? 0 : thd->variables.infinidb_um_mem_limit; - else - return ( thd == NULL ) ? 0 : THDVAR(thd, um_mem_limit); + return ( thd == NULL ) ? 0 : THDVAR(thd, um_mem_limit); } void set_um_mem_limit(THD* thd, ulong value) { - if(get_use_legacy_sysvars(thd)) - thd->variables.infinidb_um_mem_limit = value; - else - THDVAR(thd, um_mem_limit) = value; + THDVAR(thd, um_mem_limit) = value; } bool get_varbin_always_hex(THD* thd) { - if(get_use_legacy_sysvars(thd)) - return ( thd == NULL ) ? false : thd->variables.infinidb_varbin_always_hex; - else - return ( thd == NULL ) ? false : THDVAR(thd, varbin_always_hex); + return ( thd == NULL ) ? false : THDVAR(thd, varbin_always_hex); } void set_varbin_always_hex(THD* thd, bool value) { - if(get_use_legacy_sysvars(thd)) - thd->variables.infinidb_varbin_always_hex = value; - else - THDVAR(thd, varbin_always_hex) = value; + THDVAR(thd, varbin_always_hex) = value; } bool get_double_for_decimal_math(THD* thd) { - if(get_use_legacy_sysvars(thd)) - return ( thd == NULL ) ? false : thd->variables.infinidb_double_for_decimal_math; - else - return ( thd == NULL ) ? false : THDVAR(thd, double_for_decimal_math); + return ( thd == NULL ) ? false : THDVAR(thd, double_for_decimal_math); } void set_double_for_decimal_math(THD* thd, bool value) { - if(get_use_legacy_sysvars(thd)) - thd->variables.infinidb_double_for_decimal_math = value; - else - THDVAR(thd, double_for_decimal_math) = value; + THDVAR(thd, double_for_decimal_math) = value; } ulong get_local_query(THD* thd) { - if(get_use_legacy_sysvars(thd)) - return ( thd == NULL ) ? 0 : thd->variables.infinidb_local_query; - else - return ( thd == NULL ) ? 0 : THDVAR(thd, local_query); + return ( thd == NULL ) ? 0 : THDVAR(thd, local_query); } void set_local_query(THD* thd, ulong value) { - if(get_use_legacy_sysvars(thd)) - thd->variables.infinidb_local_query = value; - else - THDVAR(thd, local_query) = value; + THDVAR(thd, local_query) = value; } bool get_use_import_for_batchinsert(THD* thd) { - if(get_use_legacy_sysvars(thd)) - return ( thd == NULL ) ? false : thd->variables.infinidb_use_import_for_batchinsert; - else - return ( thd == NULL ) ? false : THDVAR(thd, use_import_for_batchinsert); + return ( thd == NULL ) ? false : THDVAR(thd, use_import_for_batchinsert); } void set_use_import_for_batchinsert(THD* thd, bool value) { - if(get_use_legacy_sysvars(thd)) - thd->variables.infinidb_use_import_for_batchinsert = value; - else - THDVAR(thd, use_import_for_batchinsert) = value; + THDVAR(thd, use_import_for_batchinsert) = value; } ulong get_import_for_batchinsert_delimiter(THD* thd) { - if(get_use_legacy_sysvars(thd)) - return ( thd == NULL ) ? 0 : thd->variables.infinidb_import_for_batchinsert_delimiter; - else - return ( thd == NULL ) ? 0 : THDVAR(thd, import_for_batchinsert_delimiter); + return ( thd == NULL ) ? 0 : THDVAR(thd, import_for_batchinsert_delimiter); } void set_import_for_batchinsert_delimiter(THD* thd, ulong value) { - if(get_use_legacy_sysvars(thd)) - thd->variables.infinidb_import_for_batchinsert_delimiter = value; - else - THDVAR(thd, import_for_batchinsert_delimiter) = value; + THDVAR(thd, import_for_batchinsert_delimiter) = value; } ulong get_import_for_batchinsert_enclosed_by(THD* thd) { - if(get_use_legacy_sysvars(thd)) - return ( thd == NULL ) ? 0 : thd->variables.infinidb_import_for_batchinsert_enclosed_by; - else - return ( thd == NULL ) ? 0 : THDVAR(thd, import_for_batchinsert_enclosed_by); + return ( thd == NULL ) ? 0 : THDVAR(thd, import_for_batchinsert_enclosed_by); } void set_import_for_batchinsert_enclosed_by(THD* thd, ulong value) { - if(get_use_legacy_sysvars(thd)) - thd->variables.infinidb_import_for_batchinsert_enclosed_by = value; - else - THDVAR(thd, import_for_batchinsert_enclosed_by) = value; + THDVAR(thd, import_for_batchinsert_enclosed_by) = value; } diff --git a/dbcon/mysql/ha_mcs_sysvars.h b/dbcon/mysql/ha_mcs_sysvars.h index eae31b0ea..a977842bc 100644 --- a/dbcon/mysql/ha_mcs_sysvars.h +++ b/dbcon/mysql/ha_mcs_sysvars.h @@ -40,8 +40,17 @@ void set_compression_type(THD* thd, ulong value); void* get_fe_conn_info_ptr(THD* thd = NULL); void set_fe_conn_info_ptr(void* ptr, THD* thd = NULL); -bool get_use_legacy_sysvars(THD* thd); -void set_use_legacy_sysvars(THD* thd, bool value); +ulonglong get_original_optimizer_flags(THD* thd = NULL); +void set_original_optimizer_flags(ulonglong ptr, THD* thd = NULL); + +bool get_select_handler(THD* thd); +void set_select_handler(THD* thd, bool value); + +bool get_derived_handler(THD* thd); +void set_derived_handler(THD* thd, bool value); + +bool get_group_by_handler(THD* thd); +void set_group_by_handler(THD* thd, bool value); bool get_use_decimal_scale(THD* thd); void set_use_decimal_scale(THD* thd, bool value); diff --git a/dbcon/mysql/ha_subquery.h b/dbcon/mysql/ha_subquery.h index b008b4fcd..b201e2fe3 100644 --- a/dbcon/mysql/ha_subquery.h +++ b/dbcon/mysql/ha_subquery.h @@ -45,7 +45,10 @@ namespace cal_impl_if class SubQuery { public: - SubQuery(gp_walk_info& gwip) : fGwip(gwip), fCorrelated(false) {} + SubQuery(gp_walk_info& gwip) : + fGwip(gwip), + fCorrelated(false) + {} virtual ~SubQuery() {} virtual gp_walk_info& gwip() const { @@ -178,7 +181,7 @@ class FromSubQuery : public SubQuery { public: FromSubQuery(gp_walk_info&); - FromSubQuery(gp_walk_info&, SELECT_LEX* fromSub); + FromSubQuery(gp_walk_info&, SELECT_LEX* fromSub, bool isPushdownHand=false); ~FromSubQuery(); const SELECT_LEX* fromSub() const { @@ -200,6 +203,7 @@ public: private: SELECT_LEX* fFromSub; std::string fAlias; + bool fPushdownHand; }; class SelectSubQuery : public SubQuery diff --git a/dbcon/mysql/ha_view.cpp b/dbcon/mysql/ha_view.cpp index 764c2c5c5..cfcfe3970 100644 --- a/dbcon/mysql/ha_view.cpp +++ b/dbcon/mysql/ha_view.cpp @@ -102,14 +102,17 @@ void View::transform() CalpontSystemCatalog::TableAliasName tn = make_aliasview("", "", alias, viewName); gwi.tbList.push_back(tn); gwi.tableMap[tn] = make_pair(0, table_ptr); - gwi.thd->infinidb_vtable.isUnion = true; //by-pass the 2nd pass of rnd_init + // TODO MCOL-2178 isUnion member only assigned, never used + // MIGR::infinidb_vtable.isUnion = true; //by-pass the 2nd pass of rnd_init } else if (table_ptr->view) { // for nested view, the view name is vout.vin... format CalpontSystemCatalog::TableAliasName tn = make_aliasview(table_ptr->db.str, table_ptr->table_name.str, table_ptr->alias.str, viewName); gwi.viewName = make_aliastable(table_ptr->db.str, table_ptr->table_name.str, viewName); - View* view = new View(table_ptr->view->select_lex, &gwi); + // WIP MCOL-2178 CS could mess with the SELECT_LEX unit so better + // use a copy. + View* view = new View(*table_ptr->view->first_select_lex(), &gwi); view->viewName(gwi.viewName); gwi.viewList.push_back(view); view->transform(); @@ -117,7 +120,7 @@ void View::transform() else { // check foreign engine tables - bool infiniDB = (table_ptr->table ? isInfiniDB(table_ptr->table) : true); + bool infiniDB = (table_ptr->table ? isMCSTable(table_ptr->table) : true); // trigger system catalog cache if (infiniDB) diff --git a/dbcon/mysql/idb_mysql.h b/dbcon/mysql/idb_mysql.h index 25f3effcf..cb842d740 100644 --- a/dbcon/mysql/idb_mysql.h +++ b/dbcon/mysql/idb_mysql.h @@ -70,6 +70,8 @@ template bool isnan(T); #include "item_windowfunc.h" #include "sql_cte.h" #include "tztime.h" +#include "derived_handler.h" +#include "select_handler.h" // Now clean up the pollution as best we can... #undef min diff --git a/dbcon/mysql/my.cnf b/dbcon/mysql/my.cnf index fb20fd8c9..12392a664 100644 --- a/dbcon/mysql/my.cnf +++ b/dbcon/mysql/my.cnf @@ -47,21 +47,21 @@ group_concat_max_len=512 sql_mode="ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION" # Enable compression by default on create, set to 0 to turn off -infinidb_compression_type=2 +#columnstore_compression_type=2 # Default for string table threshhold -infinidb_stringtable_threshold=20 +#columnstore_stringtable_threshold=20 # infinidb local query flag -infinidb_local_query=0 +#columnstore_local_query=0 -infinidb_diskjoin_smallsidelimit=0 -infinidb_diskjoin_largesidelimit=0 -infinidb_diskjoin_bucketsize=100 -infinidb_um_mem_limit=0 +#columnstore_diskjoin_smallsidelimit=0 +#columnstore_diskjoin_largesidelimit=0 +#columnstore_diskjoin_bucketsize=100 +#columnstore_um_mem_limit=0 -infinidb_use_import_for_batchinsert=1 -infinidb_import_for_batchinsert_delimiter=7 +#columnstore_use_import_for_batchinsert=1 +#columnstore_import_for_batchinsert_delimiter=7 basedir = /usr/local/mariadb/columnstore/mysql/ character-sets-dir = /usr/local/mariadb/columnstore/mysql/share/charsets/ diff --git a/dbcon/mysql/sm.cpp b/dbcon/mysql/sm.cpp index 5df01dda6..8dc5c0414 100644 --- a/dbcon/mysql/sm.cpp +++ b/dbcon/mysql/sm.cpp @@ -373,17 +373,16 @@ status_t tpl_close ( cpsm_tplh_t* ntplh, cpsm_conhdl_t** conn_hdl, QueryStats& stats, + bool ask_4_stats, bool clear_scan_ctx) { cpsm_conhdl_t* hndl = *conn_hdl; -#if IDB_SM_DEBUG SMDEBUGLOG << "tpl_close: hndl" << hndl << " ntplh " << ntplh; if (ntplh) SMDEBUGLOG << " tableid: " << ntplh->tableid; SMDEBUGLOG << endl; -#endif delete ntplh; // determine end of result set and end of statement execution @@ -391,57 +390,60 @@ tpl_close ( cpsm_tplh_t* ntplh, { // Get the query stats ByteStream bs; - ByteStream::quadbyte qb = 3; - bs << qb; - hndl->write(bs); - + // Ask for a stats only if a user explicitly asks + if(ask_4_stats) + { + ByteStream::quadbyte qb = 3; + bs << qb; + hndl->write(bs); + } // MCOL-1601 Dispose of unused empty RowGroup if (clear_scan_ctx) { + std::cout << "tpl_close() clear_scan_ctx read" << std::endl; bs = hndl->exeMgr->read(); } -#if IDB_SM_DEBUG SMDEBUGLOG << "tpl_close hndl->exeMgr: " << hndl->exeMgr << endl; -#endif //keep reading until we get a string - //TODO: really need to fix this! Why is ExeMgr sending other stuff? - for (int tries = 0; tries < 10; tries++) + // Ask for a stats only if a user explicitly asks + if(ask_4_stats) { - bs = hndl->exeMgr->read(); + for (int tries = 0; tries < 10; tries++) + { + bs = hndl->exeMgr->read(); - if (bs.length() == 0) break; + if (bs.length() == 0) break; - try - { - bs >> hndl->queryStats; - bs >> hndl->extendedStats; - bs >> hndl->miniStats; - stats.unserialize(bs); - stats.setEndTime(); - stats.insert(); - break; + try + { + bs >> hndl->queryStats; + bs >> hndl->extendedStats; + bs >> hndl->miniStats; + stats.unserialize(bs); + stats.setEndTime(); + stats.insert(); + break; + } + catch (IDBExcept&) + { + // @bug4732 + end_query(hndl); + throw; + } + catch (...) + { + // querystats messed up. close connection. + // no need to throw for querystats protocol error, like for tablemode. + SMDEBUGLOG << "tpl_close() exception whilst getting stats" << endl; + end_query(hndl); + sm_cleanup(hndl); + *conn_hdl = 0; + return STATUS_OK; + //throw runtime_error(string("tbl_close catch exception: ") + e.what()); + } } - catch (IDBExcept&) - { - // @bug4732 - end_query(hndl); - throw; - } - catch (...) - { - // querystats messed up. close connection. - // no need to throw for querystats protocol error, like for tablemode. -#if IDB_SM_DEBUG - SMDEBUGLOG << "tpl_close() exception whilst getting stats" << endl; -#endif - end_query(hndl); - sm_cleanup(hndl); - *conn_hdl = 0; - return STATUS_OK; - //throw runtime_error(string("tbl_close catch exception: ") + e.what()); - } - } + } //stats end_query(hndl); } diff --git a/dbcon/mysql/sm.h b/dbcon/mysql/sm.h index dafa64419..32cb1aa18 100644 --- a/dbcon/mysql/sm.h +++ b/dbcon/mysql/sm.h @@ -282,7 +282,7 @@ extern status_t tpl_open(tableid_t, cpsm_tplh_t*, cpsm_conhdl_t*); extern status_t tpl_scan_open(tableid_t, sp_cpsm_tplsch_t&, cpsm_conhdl_t*); extern status_t tpl_scan_fetch(sp_cpsm_tplsch_t&, cpsm_conhdl_t*, int* k = 0); extern status_t tpl_scan_close(sp_cpsm_tplsch_t&); -extern status_t tpl_close(cpsm_tplh_t*, cpsm_conhdl_t**, querystats::QueryStats& stats, bool clear_scan_ctx = false); +extern status_t tpl_close(cpsm_tplh_t*, cpsm_conhdl_t**, querystats::QueryStats& stats, bool ask_4_stats, bool clear_scan_ctx = false); } diff --git a/utils/rowgroup/rowgroup.cpp b/utils/rowgroup/rowgroup.cpp index e16f12c30..27d530343 100644 --- a/utils/rowgroup/rowgroup.cpp +++ b/utils/rowgroup/rowgroup.cpp @@ -1591,6 +1591,7 @@ RowGroup& RowGroup::operator+=(const RowGroup& rhs) } hasLongStringField = rhs.hasLongStringField || hasLongStringField; + useStringTable = rhs.useStringTable || useStringTable; offsets = (useStringTable ? &stOffsets[0] : &oldOffsets[0]); return *this;