diff --git a/dbcon/ddlpackage/ddl-gram-win.cpp b/dbcon/ddlpackage/ddl-gram-win.cpp index a3213b6e4..cf16912bd 100644 --- a/dbcon/ddlpackage/ddl-gram-win.cpp +++ b/dbcon/ddlpackage/ddl-gram-win.cpp @@ -850,14 +850,14 @@ static const yytype_uint8 yydefact[] = static const yytype_int16 yydefgoto[] = { -1, 5, 6, 7, 8, 33, 9, 10, 320, 11, - 29, 12, 96, 97, 98, 66, 104, 105, 141, 106, - 107, 371, 372, 375, 376, 382, 385, 377, 378, 391, - 321, 276, 13, 43, 44, 45, 46, 47, 48, 49, - 25, 26, 50, 142, 68, 252, 99, 194, 253, 129, - 254, 255, 167, 168, 219, 220, 169, 256, 257, 152, - 130, 131, 132, 133, 178, 172, 134, 190, 304, 135, - 185, 237, 51, 145, 52, 71 -}; + 29, 12, 96, 97, 98, 66, 104, 105, 141, 106, + 107, 371, 372, 375, 376, 382, 385, 377, 378, 391, + 321, 276, 13, 43, 44, 45, 46, 47, 48, 49, + 25, 26, 50, 142, 68, 252, 99, 194, 253, 129, + 254, 255, 167, 168, 219, 220, 169, 256, 257, 152, + 130, 131, 132, 133, 178, 172, 134, 190, 304, 135, + 185, 237, 51, 145, 52, 71 + }; /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ @@ -910,14 +910,14 @@ static const yytype_int16 yypact[] = static const yytype_int16 yypgoto[] = { -270, -270, -270, 331, -270, -270, -270, -270, 26, -270, - -270, -270, 62, 218, 336, 314, 287, -270, -136, -270, - -270, -270, 11, -270, -270, -270, -270, 6, 1, 7, - 175, -269, -270, -270, -28, -270, -270, -270, -270, -270, - -29, 5, -270, -23, -70, -183, 79, -270, -175, -74, - -179, -223, -157, -270, -270, -270, 216, 90, -5, -202, - -270, -270, -270, -270, 161, 116, -270, 166, -270, -270, - -270, -270, -270, 119, -270, -270 -}; + -270, -270, 62, 218, 336, 314, 287, -270, -136, -270, + -270, -270, 11, -270, -270, -270, -270, 6, 1, 7, + 175, -269, -270, -270, -28, -270, -270, -270, -270, -270, + -29, 5, -270, -23, -70, -183, 79, -270, -175, -74, + -179, -223, -157, -270, -270, -270, 216, 90, -5, -202, + -270, -270, -270, -270, 161, 116, -270, 166, -270, -270, + -270, -270, -270, 119, -270, -270 + }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule which diff --git a/dbcon/ddlpackage/ddl.l b/dbcon/ddlpackage/ddl.l index 7e7400451..f7a545706 100644 --- a/dbcon/ddlpackage/ddl.l +++ b/dbcon/ddlpackage/ddl.l @@ -18,6 +18,7 @@ /* $Id: ddl.l 9341 2013-03-27 14:10:35Z chao $ */ %{ +#include #include #include #include @@ -31,7 +32,7 @@ #endif using namespace ddlpackage; -typedef enum { NOOP, STRIP_QUOTES } copy_action_t; +typedef enum { NOOP, STRIP_QUOTES, STRIP_QUOTES_FQ } copy_action_t; int lineno = 1; void ddlerror(struct pass_to_bison* x, char const *s); @@ -71,8 +72,10 @@ identifier {ident_start}{ident_cont}* extended_identifier {ident_start}{extended_ident_cont}* /* fully qualified names regexes */ fq_identifier {identifier}\.{identifier} -identifer_quoted {grave_accent}{extended_identifier}{grave_accent} -identifer_double_quoted {double_quote}{extended_identifier}{double_quote} +identifier_quoted {grave_accent}{extended_identifier}{grave_accent} +identifier_double_quoted {double_quote}{extended_identifier}{double_quote} +fq_quoted ({identifier_quoted}|{extended_identifier})\.({identifier_quoted}|{identifier}) +fq_double_quoted ({identifier_double_quoted}|{extended_identifier})\.({identifier_double_quoted}|{identifier}) integer [-+]?{digit}+ decimal ([-+]?({digit}*\.{digit}+)|({digit}+\.{digit}*)) @@ -84,9 +87,11 @@ realfail2 ({integer}|{decimal})[Ee][-+] %% -{identifer_quoted} { ddlget_lval(yyscanner)->str = scanner_copy( ddlget_text(yyscanner), yyscanner, STRIP_QUOTES ); return IDENT; } -{identifer_double_quoted} { ddlget_lval(yyscanner)->str = scanner_copy( ddlget_text(yyscanner), yyscanner, STRIP_QUOTES ); return IDENT; } +{identifier_quoted} { ddlget_lval(yyscanner)->str = scanner_copy( ddlget_text(yyscanner), yyscanner, STRIP_QUOTES ); return IDENT; } +{identifier_double_quoted} { ddlget_lval(yyscanner)->str = scanner_copy( ddlget_text(yyscanner), yyscanner, STRIP_QUOTES ); return IDENT; } {fq_identifier} { ddlget_lval(yyscanner)->str = scanner_copy(ddlget_text(yyscanner), yyscanner); return FQ_IDENT; } +{fq_quoted} { ddlget_lval(yyscanner)->str = scanner_copy(ddlget_text(yyscanner), yyscanner, STRIP_QUOTES_FQ); return FQ_IDENT; } +{fq_double_quoted} { ddlget_lval(yyscanner)->str = scanner_copy(ddlget_text(yyscanner), yyscanner, STRIP_QUOTES_FQ); return FQ_IDENT; } ACTION {return ACTION;} ADD {return ADD;} @@ -281,6 +286,57 @@ char* scanner_copy (char *str, yyscan_t yyscanner, copy_action_t action) nv[strlen(str) - 1] = '\0'; result = nv + 1; } + else if (action == STRIP_QUOTES_FQ) + { + bool move_left = false; + bool move_right = false; + char* left = nv; + char* tmp_first = nv; + // MCOL-1384 Loop through all comas in this quoted fq id + // looking for $quote_sign.$quote_sign sequence. + char* fq_delimiter; + int tmp_pos = 0; + while((fq_delimiter = strchr(tmp_first, '.')) != NULL) + { + if( (*(fq_delimiter -1) == '`' && *(fq_delimiter + 1) == '`') || + (*(fq_delimiter -1) == '"' && *(fq_delimiter + 1) == '"') ) + { + tmp_pos += fq_delimiter - tmp_first; + break; + } + tmp_first = fq_delimiter; + } + + char* fq_delimiter_orig = str + tmp_pos; + char* right = fq_delimiter + 1; + char* right_orig = fq_delimiter_orig + 1; + // MCOL-1384 Strip quotes from the left part. + if(*left == '"' || *left == '`') + { + result = left + 1; + *(fq_delimiter - 1) = '.'; + move_left = true; + } + else + { + fq_delimiter += 1; + } + + int right_length = strlen(right); + // MCOL-1384 Strip quotes from the right part. + if(*right == '`' || *right == '"') + { + right += 1; right_orig += 1; + right_length -= 2; + move_right = true; + *(fq_delimiter + right_length) = '\0'; + } + + if(move_left || move_right) + { + strncpy(fq_delimiter, right_orig, right_length); + } + } return result; } diff --git a/dbcon/dmlpackage/dml-gram-win.cpp b/dbcon/dmlpackage/dml-gram-win.cpp index d278d9340..d224d89b1 100644 --- a/dbcon/dmlpackage/dml-gram-win.cpp +++ b/dbcon/dmlpackage/dml-gram-win.cpp @@ -866,16 +866,16 @@ static const yytype_uint8 yydefact[] = static const yytype_int16 yydefgoto[] = { -1, 13, 14, 15, 128, 129, 130, 131, 295, 296, - 297, 358, 378, 298, 155, 132, 360, 105, 133, 363, - 180, 181, 182, 338, 339, 16, 188, 268, 269, 304, - 17, 18, 19, 20, 21, 22, 23, 158, 253, 254, - 24, 25, 26, 31, 27, 108, 109, 28, 101, 102, - 99, 136, 137, 138, 61, 170, 171, 214, 215, 100, - 261, 318, 290, 143, 144, 145, 146, 147, 282, 148, - 149, 278, 150, 243, 151, 192, 152, 63, 64, 65, - 66, 67, 216, 44, 68, 335, 156, 33, 69, 259, - 340, 80 -}; + 297, 358, 378, 298, 155, 132, 360, 105, 133, 363, + 180, 181, 182, 338, 339, 16, 188, 268, 269, 304, + 17, 18, 19, 20, 21, 22, 23, 158, 253, 254, + 24, 25, 26, 31, 27, 108, 109, 28, 101, 102, + 99, 136, 137, 138, 61, 170, 171, 214, 215, 100, + 261, 318, 290, 143, 144, 145, 146, 147, 282, 148, + 149, 278, 150, 243, 151, 192, 152, 63, 64, 65, + 66, 67, 216, 44, 68, 335, 156, 33, 69, 259, + 340, 80 + }; /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ @@ -930,16 +930,16 @@ static const yytype_int16 yypact[] = static const yytype_int16 yypgoto[] = { -270, -270, 489, -270, -270, -270, 375, -270, -270, 179, - -270, -270, -270, -270, -269, -270, -270, -163, -270, -270, - -270, -270, 281, -270, 145, -270, -270, -270, 204, 240, - -270, -270, -270, -270, -270, -270, -270, -270, -270, 226, - -270, -270, -270, -131, -270, -270, 354, -270, 427, 359, - -56, 386, -136, -103, -170, -216, -270, -270, 255, -270, - -270, -270, -270, -134, -270, -270, -270, -270, 242, -270, - -270, 244, -270, -270, -270, 8, -24, -270, -189, 61, - -270, 140, -11, 484, -97, -270, -72, 4, 47, -270, - 449, 443 -}; + -270, -270, -270, -270, -269, -270, -270, -163, -270, -270, + -270, -270, 281, -270, 145, -270, -270, -270, 204, 240, + -270, -270, -270, -270, -270, -270, -270, -270, -270, 226, + -270, -270, -270, -131, -270, -270, 354, -270, 427, 359, + -56, 386, -136, -103, -170, -216, -270, -270, 255, -270, + -270, -270, -270, -134, -270, -270, -270, -270, 242, -270, + -270, 244, -270, -270, -270, 8, -24, -270, -189, 61, + -270, 140, -11, 484, -97, -270, -72, 4, 47, -270, + 449, 443 + }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule which diff --git a/dbcon/joblist/jlf_tuplejoblist.cpp b/dbcon/joblist/jlf_tuplejoblist.cpp index 480b23f91..b006eb90c 100644 --- a/dbcon/joblist/jlf_tuplejoblist.cpp +++ b/dbcon/joblist/jlf_tuplejoblist.cpp @@ -487,23 +487,25 @@ void adjustLastStep(JobStepVector& querySteps, DeliveredTableMap& deliverySteps, // (jobInfo.constantCol == CONST_COL_EXIST) || // (jobInfo.hasDistinct)) // { - if (jobInfo.annexStep.get() == NULL) - jobInfo.annexStep.reset(new TupleAnnexStep(jobInfo)); + if (jobInfo.annexStep.get() == NULL) + jobInfo.annexStep.reset(new TupleAnnexStep(jobInfo)); - TupleAnnexStep* tas = dynamic_cast(jobInfo.annexStep.get()); - tas->setLimit(jobInfo.limitStart, jobInfo.limitCount); + TupleAnnexStep* tas = dynamic_cast(jobInfo.annexStep.get()); + tas->setLimit(jobInfo.limitStart, jobInfo.limitCount); - // if (jobInfo.limitCount != (uint64_t) - 1) +// if (jobInfo.limitCount != (uint64_t) - 1) // { - if (jobInfo.orderByColVec.size() > 0) - tas->addOrderBy(new LimitedOrderBy()); + if (jobInfo.orderByColVec.size() > 0) + tas->addOrderBy(new LimitedOrderBy()); + // } - if (jobInfo.constantCol == CONST_COL_EXIST) - tas->addConstant(new TupleConstantStep(jobInfo)); + if (jobInfo.constantCol == CONST_COL_EXIST) + tas->addConstant(new TupleConstantStep(jobInfo)); + + if (jobInfo.hasDistinct) + tas->setDistinct(); - if (jobInfo.hasDistinct) - tas->setDistinct(); // } if (jobInfo.annexStep) diff --git a/dbcon/joblist/limitedorderby.cpp b/dbcon/joblist/limitedorderby.cpp index 6701faf4b..82d6041a8 100644 --- a/dbcon/joblist/limitedorderby.cpp +++ b/dbcon/joblist/limitedorderby.cpp @@ -76,12 +76,14 @@ void LimitedOrderBy::initialize(const RowGroup& rg, const JobInfo& jobInfo) { map::iterator j = keyToIndexMap.find(i->first); idbassert(j != keyToIndexMap.end()); + // MCOL-1052 Ordering direction in CSEP differs from // internal direction representation. if (i->second) fOrderByCond.push_back(IdbSortSpec(j->second, false)); else fOrderByCond.push_back(IdbSortSpec(j->second, true)); + //fOrderByCond.push_back(IdbSortSpec(j->second, i->second)); } @@ -181,7 +183,7 @@ void LimitedOrderBy::finalize() fDataQueue.push(fData); // MCOL-1052 The removed check effectivly disables sorting to happen, - // since fStart = 0; + // since fStart = 0; if (true) { uint64_t newSize = fRowsPerRG * fRowGroup.getRowSize(); diff --git a/dbcon/joblist/tupleaggregatestep.cpp b/dbcon/joblist/tupleaggregatestep.cpp index 3dbd01311..9e23ac17b 100644 --- a/dbcon/joblist/tupleaggregatestep.cpp +++ b/dbcon/joblist/tupleaggregatestep.cpp @@ -1304,7 +1304,7 @@ void TupleAggregateStep::prep1PhaseAggregate( { throw logic_error("prep1PhaseAggregate: A UDAF function is called but there's no/not enough UDAFColumn/-s"); } - } + } else { funct.reset(new RowAggFunctionCol(aggOp, stats, colProj, i)); diff --git a/dbcon/mysql/ha_calpont.cpp b/dbcon/mysql/ha_calpont.cpp index aed7ffafc..35953fc34 100644 --- a/dbcon/mysql/ha_calpont.cpp +++ b/dbcon/mysql/ha_calpont.cpp @@ -123,8 +123,8 @@ static int calpont_rollback(handlerton* hton, THD* thd, bool all); static int calpont_close_connection ( handlerton* hton, THD* thd ); handlerton* calpont_hton; -static group_by_handler * -create_calpont_group_by_handler(THD *thd, Query *query); +static group_by_handler* +create_calpont_group_by_handler(THD* thd, Query* query); /* Variables for example share methods */ @@ -1142,7 +1142,7 @@ static MYSQL_SYSVAR_ULONG( /*@brief create_calpont_group_by_handler- Creates handler*/ /*********************************************************** * DESCRIPTION: - * Creates a group_by pushdown handler. + * Creates a group_by pushdown handler. * Details are in server/sql/group_by_handler.h * PARAMETERS: * thd - THD pointer. @@ -1151,21 +1151,21 @@ static MYSQL_SYSVAR_ULONG( * group_by_handler if success * NULL in other case ***********************************************************/ -static group_by_handler * -create_calpont_group_by_handler(THD *thd, Query *query) +static group_by_handler* +create_calpont_group_by_handler(THD* thd, Query* query) { - ha_calpont_group_by_handler *handler = NULL; - + ha_calpont_group_by_handler* handler = NULL; + if ( thd->infinidb_vtable.vtable_state == THD::INFINIDB_DISABLE_VTABLE ) { handler = new ha_calpont_group_by_handler(thd, query); - - // Notify the server, that CS handles GROUP BY, ORDER BY and HAVING clauses. + + // 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; } diff --git a/dbcon/mysql/ha_calpont.h b/dbcon/mysql/ha_calpont.h index d1e545fec..bcbcdc5da 100644 --- a/dbcon/mysql/ha_calpont.h +++ b/dbcon/mysql/ha_calpont.h @@ -251,13 +251,13 @@ public: /*@brief group_by_handler class*/ /*********************************************************** * DESCRIPTION: - * Provides server with group_by_handler API methods. + * 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 accordin to comments in - * server/sql/group_handler.cc. - * So the temporary table for + * select - attribute contains all GROUP BY, HAVING, ORDER items and calls it + * an extended SELECT list accordin 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. @@ -274,29 +274,29 @@ public: ***********************************************************/ class ha_calpont_group_by_handler: public group_by_handler { - public: - 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) - { } - ~ha_calpont_group_by_handler() { } - int init_scan(); - int next_row(); - int end_scan(); +public: + 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) + { } + ~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; + 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 ba9b2c299..bdce5e4ce 100644 --- a/dbcon/mysql/ha_calpont_ddl.cpp +++ b/dbcon/mysql/ha_calpont_ddl.cpp @@ -174,10 +174,6 @@ uint32_t convertDataType(int dataType) calpontDataType = CalpontSystemCatalog::DATETIME; break; - case ddlpackage::DDL_TIME: - calpontDataType = CalpontSystemCatalog::TIME; - break; - case ddlpackage::DDL_CLOB: calpontDataType = CalpontSystemCatalog::CLOB; break; @@ -1872,20 +1868,16 @@ int ProcessDDLStatement(string& ddlStatement, string& schema, const string& tabl if (ddlStatement.find("AUTO_INCREMENT") != string::npos) { thd->raise_error_printf(ER_CHECK_NOT_IMPLEMENTED, "Use of the MySQL auto_increment syntax is not supported in Columnstore. If you wish to create an auto increment column in Columnstore, please consult the Columnstore SQL Syntax Guide for the correct usage."); - } - // MCOL-867. MariaDB RENAME TABLE statement supports WAIT|NOWAIT options since 10.3.0 but Columnstore isn't yet. - else if (ddlStatement.find("WAIT") != string::npos || ddlStatement.find("NOWAIT") != string::npos) - { - thd->raise_error_printf(ER_CHECK_NOT_IMPLEMENTED, "WAIT and NOWAIT options are not supported in Columnstore. Please consult the Columnstore SQL Syntax Guide for the correct usage."); + ci->alterTableState = cal_connection_info::NOT_ALTER; + ci->isAlter = false; } else { //@Bug 1888,1885. update error message thd->raise_error_printf(ER_CHECK_NOT_IMPLEMENTED, "The syntax or the data type(s) is not supported by Columnstore. Please check the Columnstore syntax guide for supported syntax or data types."); + ci->alterTableState = cal_connection_info::NOT_ALTER; + ci->isAlter = false; } - - ci->alterTableState = cal_connection_info::NOT_ALTER; - ci->isAlter = false; } return rc; @@ -2187,7 +2179,6 @@ int ha_calpont_impl_rename_table_(const char* from, const char* to, cal_connecti THD* thd = current_thd; string emsg; - ostringstream stmt1; pair fromPair; pair toPair; string stmt; @@ -2215,20 +2206,21 @@ int ha_calpont_impl_rename_table_(const char* from, const char* to, cal_connecti return -1; } - stmt1 << "alter table " << fromPair.second << " rename to " << toPair.second << ";"; - - stmt = stmt1.str(); + // This explicitely shields both db objects with quotes that the lexer strips down later. + stmt = "alter table `" + fromPair.second + "` rename to `" + toPair.second + "`;"; string db; - if ( fromPair.first.length() != 0 ) - db = fromPair.first; - else if ( thd->db ) + if ( thd->db ) db = thd->db; + else if ( fromPair.first.length() != 0 ) + db = fromPair.first; + else + db = toPair.first; int rc = ProcessDDLStatement(stmt, db, "", tid2sid(thd->thread_id), emsg); if (rc != 0) - push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 9999, emsg.c_str()); + push_warning(thd, Sql_condition::WARN_LEVEL_ERROR, 9999, emsg.c_str()); return rc; } diff --git a/dbcon/mysql/ha_calpont_execplan.cpp b/dbcon/mysql/ha_calpont_execplan.cpp index 02fa4d8a4..e15a5eb97 100644 --- a/dbcon/mysql/ha_calpont_execplan.cpp +++ b/dbcon/mysql/ha_calpont_execplan.cpp @@ -221,7 +221,7 @@ void debug_walk(const Item* item, void* arg) case Item::FIELD_ITEM: { Item_field* ifp = (Item_field*)item; - cerr << "FIELD_ITEM: " << (ifp->db_name ? ifp->db_name : "") << '.' << bestTableName(ifp) << + cout << "FIELD_ITEM: " << (ifp->db_name ? ifp->db_name : "") << '.' << bestTableName(ifp) << '.' << ifp->field_name << endl; break; } @@ -229,10 +229,10 @@ void debug_walk(const Item* item, void* arg) case Item::INT_ITEM: { Item_int* iip = (Item_int*)item; - cerr << "INT_ITEM: "; + cout << "INT_ITEM: "; - if (iip->name) cerr << iip->name << " (from name string)" << endl; - else cerr << iip->val_int() << endl; + if (iip->name) cout << iip->name << " (from name string)" << endl; + else cout << iip->val_int() << endl; break; } @@ -243,19 +243,19 @@ void debug_walk(const Item* item, void* arg) String val, *str = isp->val_str(&val); string valStr; valStr.assign(str->ptr(), str->length()); - cerr << "STRING_ITEM: >" << valStr << '<' << endl; + cout << "STRING_ITEM: >" << valStr << '<' << endl; break; } case Item::REAL_ITEM: { - cerr << "REAL_ITEM" << endl; + cout << "REAL_ITEM" << endl; break; } case Item::DECIMAL_ITEM: { - cerr << "DECIMAL_ITEM" << endl; + cout << "DECIMAL_ITEM" << endl; break; } @@ -263,85 +263,85 @@ void debug_walk(const Item* item, void* arg) { Item_func* ifp = (Item_func*)item; Item_func_opt_neg* inp; - cerr << "FUNC_ITEM: "; + cout << "FUNC_ITEM: "; switch (ifp->functype()) { case Item_func::UNKNOWN_FUNC: // 0 - cerr << ifp->func_name() << " (" << ifp->functype() << ")" << endl; + cout << ifp->func_name() << " (" << ifp->functype() << ")" << endl; break; case Item_func::GT_FUNC: // 7 - cerr << '>' << " (" << ifp->functype() << ")" << endl; + cout << '>' << " (" << ifp->functype() << ")" << endl; break; case Item_func::EQ_FUNC: // 1 - cerr << '=' << " (" << ifp->functype() << ")" << endl; + cout << '=' << " (" << ifp->functype() << ")" << endl; break; case Item_func::GE_FUNC: - cerr << ">=" << " (" << ifp->functype() << ")" << endl; + cout << ">=" << " (" << ifp->functype() << ")" << endl; break; case Item_func::LE_FUNC: - cerr << "<=" << " (" << ifp->functype() << ")" << endl; + cout << "<=" << " (" << ifp->functype() << ")" << endl; break; case Item_func::LT_FUNC: - cerr << '<' << " (" << ifp->functype() << ")" << endl; + cout << '<' << " (" << ifp->functype() << ")" << endl; break; case Item_func::NE_FUNC: - cerr << "<>" << " (" << ifp->functype() << ")" << endl; + cout << "<>" << " (" << ifp->functype() << ")" << endl; break; case Item_func::NEG_FUNC: // 45 - cerr << "unary minus" << " (" << ifp->functype() << ")" << endl; + cout << "unary minus" << " (" << ifp->functype() << ")" << endl; break; case Item_func::IN_FUNC: // 16 inp = (Item_func_opt_neg*)ifp; - if (inp->negated) cerr << "not "; + if (inp->negated) cout << "not "; - cerr << "in" << " (" << ifp->functype() << ")" << endl; + cout << "in" << " (" << ifp->functype() << ")" << endl; break; case Item_func::BETWEEN: inp = (Item_func_opt_neg*)ifp; - if (inp->negated) cerr << "not "; + if (inp->negated) cout << "not "; - cerr << "between" << " (" << ifp->functype() << ")" << endl; + cout << "between" << " (" << ifp->functype() << ")" << endl; break; case Item_func::ISNULL_FUNC: // 10 - cerr << "is null" << " (" << ifp->functype() << ")" << endl; + cout << "is null" << " (" << ifp->functype() << ")" << endl; break; case Item_func::ISNOTNULL_FUNC: // 11 - cerr << "is not null" << " (" << ifp->functype() << ")" << endl; + cout << "is not null" << " (" << ifp->functype() << ")" << endl; break; case Item_func::NOT_ALL_FUNC: - cerr << "not_all" << " (" << ifp->functype() << ")" << endl; + cout << "not_all" << " (" << ifp->functype() << ")" << endl; break; case Item_func::NOT_FUNC: - cerr << "not_func" << " (" << ifp->functype() << ")" << endl; + cout << "not_func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::TRIG_COND_FUNC: - cerr << "trig_cond_func" << " (" << ifp->functype() << ")" << endl; + cout << "trig_cond_func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::ISNOTNULLTEST_FUNC: - cerr << "isnotnulltest_func" << " (" << ifp->functype() << ")" << endl; + cout << "isnotnulltest_func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::MULT_EQUAL_FUNC: { - cerr << "mult_equal_func:" << " (" << ifp->functype() << ")" << endl; + cout << "mult_equal_func:" << " (" << ifp->functype() << ")" << endl; Item_equal* item_eq = (Item_equal*)ifp; Item_equal_fields_iterator it(*item_eq); Item* item; @@ -349,142 +349,142 @@ void debug_walk(const Item* item, void* arg) while ((item = it++)) { Field* equal_field = it.get_curr_field(); - cerr << equal_field->field_name << endl; + cout << equal_field->field_name << endl; } break; } case Item_func::EQUAL_FUNC: - cerr << "equal func" << " (" << ifp->functype() << ")" << endl; + cout << "equal func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::FT_FUNC: - cerr << "ft func" << " (" << ifp->functype() << ")" << endl; + cout << "ft func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::LIKE_FUNC: - cerr << "like func" << " (" << ifp->functype() << ")" << endl; + cout << "like func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::COND_AND_FUNC: - cerr << "cond and func" << " (" << ifp->functype() << ")" << endl; + cout << "cond and func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::COND_OR_FUNC: - cerr << "cond or func" << " (" << ifp->functype() << ")" << endl; + cout << "cond or func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::XOR_FUNC: - cerr << "xor func" << " (" << ifp->functype() << ")" << endl; + cout << "xor func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::INTERVAL_FUNC: - cerr << "interval func" << " (" << ifp->functype() << ")" << endl; + cout << "interval func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::SP_EQUALS_FUNC: - cerr << "sp equals func" << " (" << ifp->functype() << ")" << endl; + cout << "sp equals func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::SP_DISJOINT_FUNC: - cerr << "sp disjoint func" << " (" << ifp->functype() << ")" << endl; + cout << "sp disjoint func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::SP_INTERSECTS_FUNC: - cerr << "sp intersects func" << " (" << ifp->functype() << ")" << endl; + cout << "sp intersects func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::SP_TOUCHES_FUNC: - cerr << "sp touches func" << " (" << ifp->functype() << ")" << endl; + cout << "sp touches func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::SP_CROSSES_FUNC: - cerr << "sp crosses func" << " (" << ifp->functype() << ")" << endl; + cout << "sp crosses func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::SP_WITHIN_FUNC: - cerr << "sp within func" << " (" << ifp->functype() << ")" << endl; + cout << "sp within func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::SP_CONTAINS_FUNC: - cerr << "sp contains func" << " (" << ifp->functype() << ")" << endl; + cout << "sp contains func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::SP_OVERLAPS_FUNC: - cerr << "sp overlaps func" << " (" << ifp->functype() << ")" << endl; + cout << "sp overlaps func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::SP_STARTPOINT: - cerr << "sp startpoint func" << " (" << ifp->functype() << ")" << endl; + cout << "sp startpoint func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::SP_ENDPOINT: - cerr << "sp endpoint func" << " (" << ifp->functype() << ")" << endl; + cout << "sp endpoint func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::SP_EXTERIORRING: - cerr << "sp exteriorring func" << " (" << ifp->functype() << ")" << endl; + cout << "sp exteriorring func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::SP_POINTN: - cerr << "sp pointn func" << " (" << ifp->functype() << ")" << endl; + cout << "sp pointn func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::SP_GEOMETRYN: - cerr << "sp geometryn func" << " (" << ifp->functype() << ")" << endl; + cout << "sp geometryn func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::SP_INTERIORRINGN: - cerr << "sp exteriorringn func" << " (" << ifp->functype() << ")" << endl; + cout << "sp exteriorringn func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::SP_RELATE_FUNC: - cerr << "sp relate func" << " (" << ifp->functype() << ")" << endl; + cout << "sp relate func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::NOW_FUNC: - cerr << "now func" << " (" << ifp->functype() << ")" << endl; + cout << "now func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::SUSERVAR_FUNC: - cerr << "suservar func" << " (" << ifp->functype() << ")" << endl; + cout << "suservar func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::GUSERVAR_FUNC: - cerr << "guservar func" << " (" << ifp->functype() << ")" << endl; + cout << "guservar func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::COLLATE_FUNC: - cerr << "collate func" << " (" << ifp->functype() << ")" << endl; + cout << "collate func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::EXTRACT_FUNC: - cerr << "extract func" << " (" << ifp->functype() << ")" << endl; + cout << "extract func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::CHAR_TYPECAST_FUNC: - cerr << "char typecast func" << " (" << ifp->functype() << ")" << endl; + cout << "char typecast func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::FUNC_SP: - cerr << "func sp func" << " (" << ifp->functype() << ")" << endl; + cout << "func sp func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::UDF_FUNC: - cerr << "udf func" << " (" << ifp->functype() << ")" << endl; + cout << "udf func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::GSYSVAR_FUNC: - cerr << "gsysvar func" << " (" << ifp->functype() << ")" << endl; + cout << "gsysvar func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::DYNCOL_FUNC: - cerr << "dyncol func" << " (" << ifp->functype() << ")" << endl; + cout << "dyncol func" << " (" << ifp->functype() << ")" << endl; break; default: - cerr << "type=" << ifp->functype() << endl; + cout << "type=" << ifp->functype() << endl; break; } @@ -494,7 +494,7 @@ void debug_walk(const Item* item, void* arg) case Item::COND_ITEM: { Item_cond* icp = (Item_cond*)item; - cerr << "COND_ITEM: " << icp->func_name() << endl; + cout << "COND_ITEM: " << icp->func_name() << endl; break; } @@ -503,17 +503,7 @@ void debug_walk(const Item* item, void* arg) Item_sum* isp = (Item_sum*)item; char* item_name = item->name; - // MCOL-1052 This is an extended SELECT list item - if (!item_name && isp->get_arg_count() && isp->get_arg(0)->name) - { - item_name = isp->get_arg(0)->name; - } - else if (!item_name && isp->get_arg_count() - && isp->get_arg(0)->type() == Item::INT_ITEM) - { - item_name = (char*)"INT||*"; - } - else if (!item_name) + if (!item_name) { item_name = (char*)""; } @@ -521,39 +511,39 @@ void debug_walk(const Item* item, void* arg) switch (isp->sum_func()) { case Item_sum::SUM_FUNC: - cerr << "SUM_FUNC: " << item_name << endl; + cout << "SUM_FUNC: " << item_name << endl; break; case Item_sum::SUM_DISTINCT_FUNC: - cerr << "SUM_DISTINCT_FUNC: " << item_name << endl; + cout << "SUM_DISTINCT_FUNC: " << item_name << endl; break; case Item_sum::AVG_FUNC: - cerr << "AVG_FUNC: " << item_name << endl; + cout << "AVG_FUNC: " << item_name << endl; break; case Item_sum::COUNT_FUNC: - cerr << "COUNT_FUNC: " << item_name << endl; + cout << "COUNT_FUNC: " << item_name << endl; break; case Item_sum::COUNT_DISTINCT_FUNC: - cerr << "COUNT_DISTINCT_FUNC: " << item_name << endl; + cout << "COUNT_DISTINCT_FUNC: " << item_name << endl; break; case Item_sum::MIN_FUNC: - cerr << "MIN_FUNC: " << item_name << endl; + cout << "MIN_FUNC: " << item_name << endl; break; case Item_sum::MAX_FUNC: - cerr << "MAX_FUNC: " << item_name << endl; + cout << "MAX_FUNC: " << item_name << endl; break; case Item_sum::UDF_SUM_FUNC: - cerr << "UDAF_FUNC: " << item_name << endl; + cout << "UDAF_FUNC: " << item_name << endl; break; default: - cerr << "SUM_FUNC_ITEM type=" << isp->sum_func() << endl; + cout << "SUM_FUNC_ITEM type=" << isp->sum_func() << endl; break; } @@ -563,24 +553,24 @@ void debug_walk(const Item* item, void* arg) case Item::SUBSELECT_ITEM: { Item_subselect* sub = (Item_subselect*)item; - cerr << "SUBSELECT Item: "; + cout << "SUBSELECT Item: "; switch (sub->substype()) { case Item_subselect::EXISTS_SUBS: - cerr << "EXISTS"; + cout << "EXISTS"; break; case Item_subselect::IN_SUBS: - cerr << "IN"; + cout << "IN"; break; default: - cerr << sub->substype(); + cout << sub->substype(); break; } - cerr << endl; + cout << endl; JOIN* join = sub->get_select_lex()->join; if (join) @@ -591,7 +581,7 @@ void debug_walk(const Item* item, void* arg) cond->traverse_cond(debug_walk, arg, Item::POSTFIX); } - cerr << "Finish subselect item traversing" << endl; + cout << "Finish subselect item traversing" << endl; break; } @@ -609,14 +599,14 @@ void debug_walk(const Item* item, void* arg) //ifp->cached_table->select_lex->select_number gives the select level. // could be used on alias. // could also be used to tell correlated join (equal level). - cerr << "CACHED REF FIELD_ITEM: " << ifp->db_name << '.' << bestTableName(ifp) << + cout << "CACHED REF FIELD_ITEM: " << ifp->db_name << '.' << bestTableName(ifp) << '.' << ifp->field_name << endl; break; } else if (field->type() == Item::FUNC_ITEM) { Item_func* ifp = (Item_func*)field; - cerr << "CACHED REF FUNC_ITEM " << ifp->func_name() << endl; + cout << "CACHED REF FUNC_ITEM " << ifp->func_name() << endl; } else if (field->type() == Item::REF_ITEM) { @@ -696,43 +686,34 @@ void debug_walk(const Item* item, void* arg) } } - cerr << "CACHED REF_ITEM: ref type " << refType.c_str() << " real type " << realType.c_str() << endl; + cout << "CACHED REF_ITEM: ref type " << refType.c_str() << " real type " << realType.c_str() << endl; break; } else { - cerr << "REF_ITEM with CACHE_ITEM type unknown " << field->type() << endl; + cout << "REF_ITEM with CACHE_ITEM type unknown " << field->type() << endl; } } else if (ref->real_item()->type() == Item::FIELD_ITEM) { Item_field* ifp = (Item_field*)ref->real_item(); - // MCOL-1052 The field referenced presumable came from - // extended SELECT list. - if ( !ifp->field_name ) - { - cerr << "REF extra FIELD_ITEM: " << ifp->name << endl; - } - else - { - cerr << "REF FIELD_ITEM: " << ifp->db_name << '.' << bestTableName(ifp) << '.' << - ifp->field_name << endl; - } + cout << "REF FIELD_ITEM: " << ifp->db_name << '.' << bestTableName(ifp) << '.' << + ifp->field_name << endl; break; } else if (ref->real_item()->type() == Item::FUNC_ITEM) { Item_func* ifp = (Item_func*)ref->real_item(); - cerr << "REF FUNC_ITEM " << ifp->func_name() << endl; + cout << "REF FUNC_ITEM " << ifp->func_name() << endl; } else if (ref->real_item()->type() == Item::WINDOW_FUNC_ITEM) { Item_window_func* ifp = (Item_window_func*)ref->real_item(); - cerr << "REF WINDOW_FUNC_ITEM " << ifp->window_func()->func_name() << endl; + cout << "REF WINDOW_FUNC_ITEM " << ifp->window_func()->func_name() << endl; } else { - cerr << "UNKNOWN REF ITEM type " << ref->real_item()->type() << endl; + cout << "UNKNOWN REF ITEM type " << ref->real_item()->type() << endl; } break; @@ -741,7 +722,7 @@ void debug_walk(const Item* item, void* arg) case Item::ROW_ITEM: { Item_row* row = (Item_row*)item; - cerr << "ROW_ITEM: " << endl; + cout << "ROW_ITEM: " << endl; for (uint32_t i = 0; i < row->cols(); i++) debug_walk(row->element_index(i), 0); @@ -751,7 +732,7 @@ void debug_walk(const Item* item, void* arg) case Item::EXPR_CACHE_ITEM: { - cerr << "Expr Cache Item" << endl; + cout << "Expr Cache Item" << endl; ((Item_cache_wrapper*)item)->get_orig_item()->traverse_cond(debug_walk, arg, Item::POSTFIX); break; } @@ -766,27 +747,27 @@ void debug_walk(const Item* item, void* arg) switch (item->result_type()) { case STRING_RESULT: - cerr << "CACHE_STRING_ITEM" << endl; + cout << "CACHE_STRING_ITEM" << endl; break; case REAL_RESULT: - cerr << "CACHE_REAL_ITEM " << isp->val_real() << endl; + cout << "CACHE_REAL_ITEM " << isp->val_real() << endl; break; case INT_RESULT: - cerr << "CACHE_INT_ITEM " << isp->val_int() << endl; + cout << "CACHE_INT_ITEM " << isp->val_int() << endl; break; case ROW_RESULT: - cerr << "CACHE_ROW_ITEM" << endl; + cout << "CACHE_ROW_ITEM" << endl; break; case DECIMAL_RESULT: - cerr << "CACHE_DECIMAL_ITEM " << isp->val_decimal() << endl; + cout << "CACHE_DECIMAL_ITEM " << isp->val_decimal() << endl; break; default: - cerr << "CACHE_UNKNOWN_ITEM" << endl; + cout << "CACHE_UNKNOWN_ITEM" << endl; break; } @@ -799,7 +780,7 @@ void debug_walk(const Item* item, void* arg) //ifp->cached_table->select_lex->select_number gives the select level. // could be used on alias. // could also be used to tell correlated join (equal level). - cerr << "CACHED FIELD_ITEM: " << ifp->db_name << '.' << bestTableName(ifp) << + cout << "CACHED FIELD_ITEM: " << ifp->db_name << '.' << bestTableName(ifp) << '.' << ifp->field_name << endl; break; } @@ -881,18 +862,18 @@ void debug_walk(const Item* item, void* arg) } } - cerr << "CACHE_ITEM ref type " << refType.c_str() << " real type " << realType.c_str() << endl; + cout << "CACHE_ITEM ref type " << refType.c_str() << " real type " << realType.c_str() << endl; break; } else if (field->type() == Item::FUNC_ITEM) { Item_func* ifp = (Item_func*)field; - cerr << "CACHE_ITEM FUNC_ITEM " << ifp->func_name() << endl; + cout << "CACHE_ITEM FUNC_ITEM " << ifp->func_name() << endl; break; } else { - cerr << "CACHE_ITEM type unknown " << field->type() << endl; + cout << "CACHE_ITEM type unknown " << field->type() << endl; } break; @@ -903,12 +884,12 @@ void debug_walk(const Item* item, void* arg) String val, *str = NULL; Item_temporal_literal* itp = (Item_temporal_literal*)item; str = itp->val_str(&val); - cerr << "DATE ITEM: "; + cout << "DATE ITEM: "; if (str) - cerr << ": (" << str->ptr() << ')' << endl; + cout << ": (" << str->ptr() << ')' << endl; else - cerr << ": " << endl; + cout << ": " << endl; break; } @@ -916,18 +897,13 @@ void debug_walk(const Item* item, void* arg) case Item::WINDOW_FUNC_ITEM: { Item_window_func* ifp = (Item_window_func*)item; - cerr << "Window Function Item " << ifp->window_func()->func_name() << endl; - break; - } - - case Item::NULL_ITEM: - { - cerr << "NULL item" << endl; + cout << "Window Function Item " << ifp->window_func()->func_name() << endl; break; } + default: { - cerr << "UNKNOWN_ITEM type " << item->type() << endl; + cout << "UNKNOWN_ITEM type " << item->type() << endl; break; } } @@ -1006,8 +982,8 @@ uint32_t buildOuterJoin(gp_walk_info& gwi, SELECT_LEX& select_lex) // View is already processed in view::transform // @bug5319. view is sometimes treated as derived table and // fromSub::transform does not build outer join filters. - //if (!table_ptr->derived && table_ptr->view) - // continue; + if (!table_ptr->derived && table_ptr->view) + continue; CalpontSystemCatalog:: TableAliasName tan = make_aliasview( (table_ptr->db ? table_ptr->db : ""), @@ -1039,11 +1015,11 @@ uint32_t buildOuterJoin(gp_walk_info& gwi, SELECT_LEX& select_lex) #ifdef DEBUG_WALK_COND if (table_ptr->alias) - cerr << table_ptr->alias ; + cout << table_ptr->alias ; else if (table_ptr->alias) - cerr << table_ptr->alias; + cout << table_ptr->alias; - cerr << " outer table expression: " << endl; + cout << " outer table expression: " << endl; expr->traverse_cond(debug_walk, &gwi_outer, Item::POSTFIX); #endif expr->traverse_cond(gp_walk, &gwi_outer, Item::POSTFIX); @@ -1077,13 +1053,13 @@ uint32_t buildOuterJoin(gp_walk_info& gwi, SELECT_LEX& select_lex) Item_cond* expr = reinterpret_cast(table_ptr->embedding->on_expr); #ifdef DEBUG_WALK_COND - cerr << "inner tables: " << endl; + cout << "inner tables: " << endl; set::const_iterator it; for (it = gwi_outer.innerTables.begin(); it != gwi_outer.innerTables.end(); ++it) - cerr << (*it) << " "; + cout << (*it) << " "; - cerr << endl; + cout << endl; expr->traverse_cond(debug_walk, &gwi_outer, Item::POSTFIX); #endif expr->traverse_cond(gp_walk, &gwi_outer, Item::POSTFIX); @@ -1509,7 +1485,7 @@ bool buildPredicateItem(Item_func* ifp, gp_walk_info* gwip) // @bug5811. This filter string is for cross engine to use. // Use real table name. ifp->print(&str, QT_INFINIDB_DERIVED); - IDEBUG(cerr << str.ptr() << endl); + IDEBUG(cout << str.ptr() << endl); if (str.ptr()) cf->data(str.c_ptr()); @@ -1835,7 +1811,7 @@ bool buildPredicateItem(Item_func* ifp, gp_walk_info* gwip) (current_thd->lex->sql_command == SQLCOM_DELETE) || (current_thd->lex->sql_command == SQLCOM_DELETE_MULTI))) { - IDEBUG( cerr << "deleted func with 2 const columns" << endl ); + IDEBUG( cout << "deleted func with 2 const columns" << endl ); delete rhs; delete lhs; return false; @@ -1889,7 +1865,7 @@ bool buildPredicateItem(Item_func* ifp, gp_walk_info* gwip) if (notInner) { lhs->returnAll(true); - IDEBUG( cerr << "setting returnAll on " << tan_lhs << endl); + IDEBUG( cout << "setting returnAll on " << tan_lhs << endl); } } @@ -1906,7 +1882,7 @@ bool buildPredicateItem(Item_func* ifp, gp_walk_info* gwip) if (notInner) { rhs->returnAll(true); - IDEBUG( cerr << "setting returnAll on " << tan_rhs << endl ); + IDEBUG( cout << "setting returnAll on " << tan_rhs << endl ); } } @@ -2615,7 +2591,7 @@ CalpontSystemCatalog::ColType fieldType_MysqlToIDB (const Field* field) break; default: - IDEBUG( cerr << "fieldType_MysqlToIDB:: Unknown result type of MySQL " + IDEBUG( cout << "fieldType_MysqlToIDB:: Unknown result type of MySQL " << field->result_type() << endl ); break; } @@ -2742,7 +2718,7 @@ ReturnedColumn* buildReturnedColumn(Item* item, gp_walk_info& gwi, bool& nonSupp if ( gwi.thd) { - //if ( ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE ) || ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE_MULTI )) + if ( ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE ) || ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE_MULTI )) { if ( !item->fixed) { @@ -2932,7 +2908,7 @@ ReturnedColumn* buildReturnedColumn(Item* item, gp_walk_info& gwi, bool& nonSupp { // TODO: item is a Item_cache_wrapper printf("EXPR_CACHE_ITEM in buildReturnedColumn\n"); - cerr << "EXPR_CACHE_ITEM in buildReturnedColumn" << endl; + cout << "EXPR_CACHE_ITEM in buildReturnedColumn" << endl; break; } @@ -3537,6 +3513,18 @@ ReturnedColumn* buildFunctionColumn(Item_func* ifp, gp_walk_info& gwi, bool& non fc->functionParms(funcParms); fc->resultType(colType_MysqlToIDB(ifp)); + // add the sign for addtime function + if (funcName == "add_time") + { + Item_func_add_time* addtime = (Item_func_add_time*)ifp; + sptp.reset(new ParseTree(new ConstantColumn((int64_t)addtime->get_sign()))); + funcParms.push_back(sptp); + } + + fc->functionName(funcName); + fc->functionParms(funcParms); + fc->resultType(colType_MysqlToIDB(ifp)); + // MySQL give string result type for date function, but has the flag set. // we should set the result type to be datetime for comparision. if (ifp->field_type() == MYSQL_TYPE_DATETIME || @@ -4006,7 +3994,7 @@ ParseTree* buildParseTree(Item_func* item, gp_walk_info& gwi, bool& nonSupport) Item_cond* icp = (Item_cond*)item; #ifdef DEBUG_WALK_COND // debug - cerr << "Build Parsetree: " << endl; + cout << "Build Parsetree: " << endl; icp->traverse_cond(debug_walk, &gwi, Item::POSTFIX); #endif //@bug5044. PPSTFIX walking should always be treated as WHERE clause filter @@ -4467,7 +4455,7 @@ ReturnedColumn* buildAggregateColumn(Item* item, gp_walk_info& gwi) } else if (ac->constCol()) { - gwi.count_asterisk_list.push_back(ac); + gwi.count_asterisk_list.push_back(ac); } // For UDAF, populate the context and call the UDAF init() function. @@ -4853,7 +4841,7 @@ void gp_walk(const Item* item, void* arg) gwip->rcWorkStack.push(cc); if (str) - IDEBUG( cerr << "Const F&E " << item->full_name() << " evaluate: " << valStr << endl ); + IDEBUG( cout << "Const F&E " << item->full_name() << " evaluate: " << valStr << endl ); break; } @@ -5056,11 +5044,7 @@ void gp_walk(const Item* item, void* arg) gwip->clauseType = SELECT; if (col->type() != Item::COND_ITEM) - { rc = buildReturnedColumn(col, *gwip, gwip->fatalParseError); - if ( col->type() == Item::FIELD_ITEM ) - gwip->fatalParseError = false; - } SimpleColumn* sc = dynamic_cast(rc); @@ -5132,26 +5116,6 @@ void gp_walk(const Item* item, void* arg) Item_func* ifp = (Item_func*)col; gwip->ptWorkStack.push(buildParseTree(ifp, *gwip, gwip->fatalParseError)); } - else if (col->type() == Item::FIELD_ITEM && gwip->clauseType == HAVING) - { - Item_field* ifip = static_cast(col); - std::vector::iterator iter = gwip->havingAggColsItems.begin(); - Item_func_or_sum *isfp = NULL; - for( ;iter != gwip->havingAggColsItems.end(); iter++ ) - { - Item *temp_isfp = *iter; - isfp = reinterpret_cast(temp_isfp); - if ( isfp->type() == Item::SUM_FUNC_ITEM && - isfp->result_field == ifip->field ) - { - ReturnedColumn* rc = buildAggregateColumn(isfp, *gwip); - if (rc) - gwip->rcWorkStack.push(rc); - break; - } - } - break; - } else cando = false; @@ -5437,7 +5401,7 @@ void parse_item (Item* item, vector& field_vec, bool& hasNonSupport } else { - cerr << "UNKNOWN REF Item" << endl; + cout << "UNKNOWN REF Item" << endl; break; } } @@ -5509,7 +5473,7 @@ bool isInfiniDB(TABLE* table_ptr) int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool isUnion) { #ifdef DEBUG_WALK_COND - cerr << "getSelectPlan()" << endl; + cout << "getSelectPlan()" << endl; #endif // by pass the derived table resolve phase of mysql @@ -5596,7 +5560,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i while ((sj_nest = sj_list_it++)) { - cerr << sj_nest->db << "." << sj_nest->table_name << endl; + cout << sj_nest->db << "." << sj_nest->table_name << endl; } #endif @@ -5680,7 +5644,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i CalpontSystemCatalog::TableAliasName tan = make_aliastable(table_ptr->db, table_name, table_ptr->alias, infiniDB); gwi.tableMap[tan] = make_pair(0, table_ptr); #ifdef DEBUG_WALK_COND - cerr << tn << endl; + cout << tn << endl; #endif } } @@ -5760,15 +5724,15 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i distUnionNum = unionVec.size(); /*#ifdef DEBUG_WALK_COND - IDEBUG( cerr << ">>>> UNION DEBUG" << endl ); + IDEBUG( cout << ">>>> UNION DEBUG" << endl ); JOIN* join = sl->join; Item_cond* icp = 0; if (join != 0) icp = reinterpret_cast(join->conds); if (icp) icp->traverse_cond(debug_walk, &gwi, Item::POSTFIX); - IDEBUG ( cerr << *plan << endl ); - IDEBUG ( cerr << "<<<traverse_cond(debug_walk, &gwi, Item::POSTFIX); - cerr << "------------------------------------------------\n" << endl; + cout << "------------------------------------------------\n" << endl; #endif icp->traverse_cond(gp_walk, &gwi, Item::POSTFIX); @@ -5845,16 +5809,16 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i TABLE_LIST* curr = *tbl; if (curr->table_name) - cerr << curr->table_name << " "; + cout << curr->table_name << " "; else - cerr << curr->alias << endl; + cout << curr->alias << endl; if (curr->outer_join) - cerr << " is inner table" << endl; + cout << " is inner table" << endl; else if (curr->straight) - cerr << "straight_join" << endl; + cout << "straight_join" << endl; else - cerr << "join" << endl; + cout << "join" << endl; if (curr->nested_join) { @@ -5870,7 +5834,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i for (TABLE_LIST** tb = inner; tb < end1; tb++) { TABLE_LIST* curr1 = *tb; - cerr << curr1->alias << endl; + cout << curr1->alias << endl; if (curr1->sj_on_expr) { @@ -5945,7 +5909,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i gwi.clauseType = SELECT; #ifdef DEBUG_WALK_COND { - cerr << "------------------- SELECT --------------------" << endl; + cout << "------------------- SELECT --------------------" << endl; List_iterator_fast it(select_lex.item_list); Item* item; @@ -5954,7 +5918,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i debug_walk(item, 0); } - cerr << "-----------------------------------------------\n" << endl; + cout << "-----------------------------------------------\n" << endl; } #endif @@ -6412,7 +6376,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i } #ifdef DEBUG_WALK_COND - cerr << "SELECT clause SUBSELECT Item: " << sub->substype() << endl; + cout << "SELECT clause SUBSELECT Item: " << sub->substype() << endl; JOIN* join = sub->get_select_lex()->join; if (join) @@ -6423,7 +6387,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i cond->traverse_cond(debug_walk, &gwi, Item::POSTFIX); } - cerr << "Finish SELECT clause subselect item traversing" << endl; + cout << "Finish SELECT clause subselect item traversing" << endl; #endif SelectSubQuery* selectSub = new SelectSubQuery(gwi, sub); //selectSub->gwip(&gwi); @@ -6542,9 +6506,9 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i { Item_cond* having = reinterpret_cast(select_lex.having); #ifdef DEBUG_WALK_COND - cerr << "------------------- HAVING ---------------------" << endl; + cout << "------------------- HAVING ---------------------" << endl; having->traverse_cond(debug_walk, &gwi, Item::POSTFIX); - cerr << "------------------------------------------------\n" << endl; + cout << "------------------------------------------------\n" << endl; #endif having->traverse_cond(gp_walk, &gwi, Item::POSTFIX); @@ -6948,22 +6912,2450 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i algorithm::to_lower(lower_create_query); 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. - for (; ordercol; ordercol = ordercol->next) + // Group by list. not valid for union main query + if (gwi.thd->infinidb_vtable.vtable_state == THD::INFINIDB_CREATE_VTABLE && !unionSel) { - if ((*(ordercol->item))->type() == Item::WINDOW_FUNC_ITEM) - gwi.hasWindowFunc = true; + gwi.clauseType = GROUP_BY; + Item* nonSupportItem = NULL; + ORDER* groupcol = reinterpret_cast(select_lex.group_list.first); + + // check if window functions are in order by. InfiniDB process order by list if + // window functions are involved, either in order by or projection. + for (; ordercol; ordercol = ordercol->next) + { + if ((*(ordercol->item))->type() == Item::WINDOW_FUNC_ITEM) + gwi.hasWindowFunc = true; + } + + // 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) + { + for (; ordercol; ordercol = ordercol->next) + { + ReturnedColumn* rc = NULL; + + if (ordercol->in_field_list && ordercol->counter_used) + { + rc = gwi.returnedCols[ordercol->counter - 1]->clone(); + rc->orderPos(ordercol->counter - 1); + // can not be optimized off if used in order by with counter. + // set with self derived table alias if it's derived table + gwi.returnedCols[ordercol->counter - 1]->incRefCount(); + } + else + { + 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(); + 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. + if (!rc || gwi.fatalParseError) + { + Item* item_ptr = ordercol->item_ptr; + + while (item_ptr->type() == Item::REF_ITEM) + item_ptr = *(((Item_ref*)item_ptr)->ref); + + rc = buildReturnedColumn(item_ptr, gwi, gwi.fatalParseError); + } + + if (!rc) + { + string emsg = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_ORDER_BY); + gwi.parseErrorText = emsg; + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, emsg, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + } + + if (ordercol->direction == ORDER::ORDER_ASC) + rc->asc(true); + else + rc->asc(false); + + gwi.orderByCols.push_back(SRCP(rc)); + } + } + else if (!isUnion) + { + vector fieldVec; + bool addToSel; + + // the following order by is just for redo phase + if (!unionSel) + { + for (; ordercol; ordercol = ordercol->next) + { + Item* ord_item = *(ordercol->item); + + // @bug5993. Could be nested ref. + 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 += ", "; + + addToSel = true; + string fullname; + + if (ordercol->in_field_list && ordercol->counter_used) + { + 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) + { + ord_cols += ord_item->name; + 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; + } + } + } + else if (ord_item->type() == Item::SUBSELECT_ITEM) + { + string emsg = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_ORDER_BY); + 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; + + Item_sum* ifp = (Item_sum*)(*(ordercol->item)); + // @bug3477. add aggregate column to the select list of the create phase. + ac = buildAggregateColumn(ifp, gwi); + + if (!ac) + { + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, + IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_ORDER_BY), gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + + // check if this order by column is on the select list + for (uint32_t i = 0; i < gwi.returnedCols.size(); i++) + { + AggregateColumn* ret = dynamic_cast(gwi.returnedCols[i].get()); + + 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"; + + continue; + } + } + else if (ord_item->name && ord_item->type() == Item::FIELD_ITEM) + { + 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++) + { + 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, 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) + { + gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_ORDERBY_NOT_IN_DISTINCT); + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + + bool hasNonSupportItem = false; + uint16_t parseInfo = 0; + parse_item(ord_item, fieldVec, hasNonSupportItem, parseInfo); + + if (hasNonSupportItem) + { + string emsg = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_ORDER_BY); + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, emsg, gwi); + 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"; + } + } + + redo = (redo || fieldVec.size() != 0); + + // populate string to be added to the select list for order by + for (uint32_t i = 0; i < fieldVec.size(); i++) + { + SimpleColumn* sc = buildSimpleColumn(fieldVec[i], gwi); + + if (!sc) + { + string emsg = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_ORDER_BY); + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, emsg, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + + String str; + fieldVec[i]->print(&str, QT_INFINIDB_NO_QUOTE); + sc->alias(string(str.c_ptr())); + SRCP srcp(sc); + uint32_t j = 0; + + for (; j < gwi.returnedCols.size(); j++) + { + if (sc->sameColumn(gwi.returnedCols[j].get())) + { + SimpleColumn* field = dynamic_cast(gwi.returnedCols[j].get()); + + if (field && field->alias() == sc->alias()) + break; + } + } + + 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), srcp)); + TABLE_LIST* tmp = (fieldVec[i]->cached_table ? fieldVec[i]->cached_table : 0); + gwi.tableMap[make_aliastable(sc->schemaName(), sc->tableName(), sc->tableAlias(), sc->isInfiniDB())] = + make_pair(1, tmp); + } + } + } + + // make sure columnmap, returnedcols and count(*) arg_list are not empty + TableMap::iterator tb_iter = gwi.tableMap.begin(); + + try + { + for (; tb_iter != gwi.tableMap.end(); tb_iter++) + { + if ((*tb_iter).second.first == 1) continue; + + CalpontSystemCatalog::TableAliasName tan = (*tb_iter).first; + CalpontSystemCatalog::TableName tn = make_table((*tb_iter).first.schema, (*tb_iter).first.table); + SimpleColumn* sc = getSmallestColumn(csc, tn, tan, (*tb_iter).second.second->table, gwi); + SRCP srcp(sc); + gwi.columnMap.insert(CalpontSelectExecutionPlan::ColumnMap::value_type(sc->columnName(), srcp)); + (*tb_iter).second.first = 1; + } + } + catch (runtime_error& e) + { + setError(gwi.thd, ER_INTERNAL_ERROR, e.what(), gwi); + CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); + return ER_INTERNAL_ERROR; + } + catch (...) + { + string emsg = IDBErrorInfo::instance()->errorMsg(ERR_LOST_CONN_EXEMGR); + setError(gwi.thd, ER_INTERNAL_ERROR, emsg, gwi); + CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); + return ER_INTERNAL_ERROR; + } + + if (!gwi.count_asterisk_list.empty() || !gwi.no_parm_func_list.empty() || + gwi.returnedCols.empty()) + { + // get the smallest column from colmap + CalpontSelectExecutionPlan::ColumnMap::const_iterator iter; + int minColWidth = 0; + CalpontSystemCatalog::ColType ct; + + try + { + for (iter = gwi.columnMap.begin(); iter != gwi.columnMap.end(); ++iter) + { + // should always not null + SimpleColumn* sc = dynamic_cast(iter->second.get()); + + if (sc && !(sc->joinInfo() & JOIN_CORRELATED)) + { + ct = csc->colType(sc->oid()); + + if (minColWidth == 0) + { + minColWidth = ct.colWidth; + minSc = iter->second; + } + else if (ct.colWidth < minColWidth) + { + minColWidth = ct.colWidth; + minSc = iter->second; + } + } + } + } + catch (...) + { + string emsg = IDBErrorInfo::instance()->errorMsg(ERR_LOST_CONN_EXEMGR); + setError(gwi.thd, ER_INTERNAL_ERROR, emsg, gwi); + CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); + return ER_INTERNAL_ERROR; + } + + if (gwi.returnedCols.empty() && gwi.additionalRetCols.empty()) + gwi.returnedCols.push_back(minSc); + } + + 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).find("$vtable") != string::npos) + continue; + + if (table_ptr->derived) + { + if (aliasSet.find(table_ptr->alias) != 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); + firstTb = false; + aliasSet.insert(table_ptr->alias); + } + else if (table_ptr->view) + { + if (aliasSet.find(table_ptr->alias) != aliasSet.end()) + continue; + + if (!firstTb) + create_query += ", "; + + create_query += string(table_ptr->db) + "." + string(table_ptr->table_name) + + string(" `") + escapeBackTick(table_ptr->alias) + string("`"); + aliasSet.insert(table_ptr->alias); + 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) + "_" + + string(table_ptr->alias)) != aliasSet.end()) + continue; + + if (!firstTb) + create_query += ", "; + + create_query += string(table_ptr->db) + "." + string(table_ptr->table_name) + string(" "); + create_query += string(" `") + + escapeBackTick(table_ptr->referencing_view->alias) + "_" + + escapeBackTick(table_ptr->alias) + string("`"); + aliasSet.insert(string(table_ptr->referencing_view->alias) + "_" + + string(table_ptr->alias)); + } + else + { + if (aliasSet.find(table_ptr->alias) != aliasSet.end()) + continue; + + if (!firstTb) + create_query += ", "; + + create_query += string(table_ptr->db) + "." + string(table_ptr->table_name) + string(" "); + create_query += string("`") + escapeBackTick(table_ptr->alias) + string("`"); + aliasSet.insert(table_ptr->alias); + } + + 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 && 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) + fullname += string(field->field_name); + + 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, 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) + '`'; + } + + else if (ord_item->name) + { + // for union order by 1 case. For unknown reason, it doesn't show in_field_list + if (ord_item->type() == Item::INT_ITEM) + { + ord_cols += ord_item->name; + } + else if (ord_item->type() == Item::SUBSELECT_ITEM) + { + string emsg = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_ORDER_BY); + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, emsg, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + else + { + ord_cols += string(" `") + escapeBackTick(ord_item->name) + '`'; + } + } + else if (ord_item->type() == Item::FUNC_ITEM) + { + // @bug5636. check if this order by column is on the select list + ReturnedColumn* rc = buildFunctionColumn((Item_func*)(ord_item), gwi, gwi.fatalParseError); + + 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(); + break; + } + } + } + else + { + String str; + ord_item->print(&str, QT_INFINIDB_NO_QUOTE); + ord_cols += string(str.c_ptr()); + } + + if (ordercol->direction != ORDER::ORDER_ASC) + ord_cols += " desc"; + } + } + + if (ord_cols.length() > 0) // has order by + { + gwi.thd->infinidb_vtable.has_order_by = true; + csep->hasOrderBy(true); + ord_cols = " order by " + ord_cols; + select_query += ord_cols; + } + } + + if (unionSel || gwi.subSelectType != CalpontSelectExecutionPlan::MAIN_SELECT) + { + if (select_lex.master_unit()->global_parameters()->explicit_limit) + { + if (select_lex.master_unit()->global_parameters()->offset_limit) + { + Item_int* offset = (Item_int*)select_lex.master_unit()->global_parameters()->offset_limit; + csep->limitStart(offset->val_int()); + } + + if (select_lex.master_unit()->global_parameters()->select_limit) + { + Item_int* select = (Item_int*)select_lex.master_unit()->global_parameters()->select_limit; + 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(); + } + } + } + else if (isUnion && select_lex.explicit_limit) + { + if (select_lex.braces) + { + if (select_lex.offset_limit) + csep->limitStart(((Item_int*)select_lex.offset_limit)->val_int()); + + if (select_lex.select_limit) + csep->limitNum(((Item_int*)select_lex.select_limit)->val_int()); + } + } + else if (select_lex.explicit_limit) + { + uint32_t limitOffset = 0; + uint32_t limitNum = std::numeric_limits::max(); + + if (join) + { +#if MYSQL_VERSION_ID >= 50172 + + // @bug5729. After upgrade, join->unit sometimes is uninitialized pointer + // (not null though) and will cause seg fault. Prefer checking + // 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->select_limit && + join->select_lex->select_limit->fixed) + { + limitOffset = join->select_lex->offset_limit->val_int(); + limitNum = join->select_lex->select_limit->val_int(); + } + + else if (join->unit) + { + limitOffset = join->unit->offset_limit_cnt; + limitNum = join->unit->select_limit_cnt - limitOffset; + } + +#else + limitOffset = (join->unit)->offset_limit_cnt; + limitNum = (join->unit)->select_limit_cnt - (join->unit)->offset_limit_cnt; +#endif + } + else + { + if (select_lex.master_unit()->global_parameters()->offset_limit) + { + Item_int* offset = (Item_int*)select_lex.master_unit()->global_parameters()->offset_limit; + limitOffset = offset->val_int(); + } + + if (select_lex.master_unit()->global_parameters()->select_limit) + { + Item_int* select = (Item_int*)select_lex.master_unit()->global_parameters()->select_limit; + limitNum = select->val_int(); + } + } + + // 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()) + { + csep->limitStart(limitOffset); + csep->limitNum(limitNum); + } + else + { + ostringstream limit; + limit << " limit " << limitOffset << ", " << limitNum; + select_query += limit.str(); + } + } + + 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()) + { + gwi.fatalParseError = true; + gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_LIMIT_SUB); + setError(gwi.thd, ER_INTERNAL_ERROR, gwi.parseErrorText, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } } - // re-visit the first of ordercol list - ordercol = reinterpret_cast(order_list.first); + if (/*join->select_options*/select_lex.options & SELECT_DISTINCT) + csep->distinct(true); - // 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) + // add the smallest column to count(*) parm. + // select constant in subquery case + std::vector::iterator coliter; + + if (!minSc) { + if (!gwi.returnedCols.empty()) + minSc = gwi.returnedCols[0]; + else if (!gwi.additionalRetCols.empty()) + minSc = gwi.additionalRetCols[0]; + } + + // @bug3523, count(*) on subquery always pick column[0]. + SimpleColumn* sc = dynamic_cast(minSc.get()); + + if (sc && sc->schemaName().empty()) + { + if (gwi.derivedTbList.size() >= 1) + { + SimpleColumn* sc1 = new SimpleColumn(); + sc1->columnName(sc->columnName()); + sc1->tableName(sc->tableName()); + sc1->tableAlias(sc->tableAlias()); + sc1->viewName(lower(sc->viewName())); + sc1->colPosition(0); + minSc.reset(sc1); + } + } + + for (coliter = gwi.count_asterisk_list.begin(); coliter != gwi.count_asterisk_list.end(); ++coliter) + { + // @bug5977 @note should never throw this, but checking just in case. + // When ExeMgr fix is ready, this should not error out... + if (dynamic_cast(minSc.get())) + { + gwi.fatalParseError = true; + gwi.parseErrorText = "No project column found for aggregate function"; + setError(gwi.thd, ER_INTERNAL_ERROR, gwi.parseErrorText, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + + (*coliter)->functionParms(minSc); + } + + std::vector::iterator funciter; + + SPTP sptp(new ParseTree(minSc.get()->clone())); + + for (funciter = gwi.no_parm_func_list.begin(); funciter != gwi.no_parm_func_list.end(); ++funciter) + { + FunctionParm funcParms = (*funciter)->functionParms(); + funcParms.push_back(sptp); + (*funciter)->functionParms(funcParms); + } + + // set sequence# for subquery localCols + for (uint32_t i = 0; i < gwi.localCols.size(); i++) + gwi.localCols[i]->sequence(i); + + // append additionalRetCols to returnedCols + gwi.returnedCols.insert(gwi.returnedCols.begin(), gwi.additionalRetCols.begin(), + gwi.additionalRetCols.end()); + + csep->groupByCols(gwi.groupByCols); + csep->orderByCols(gwi.orderByCols); + csep->returnedCols(gwi.returnedCols); + csep->columnMap(gwi.columnMap); + csep->having(havingFilter); + csep->derivedTableList(gwi.derivedTbList); + csep->selectSubList(selectSubList); + csep->subSelectList(gwi.subselectList); + gwi.thd->infinidb_vtable.duplicate_field_name = false; + clearStacks(gwi); + return 0; + } + + 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; + int status = getSelectPlan(gwi, select_lex, csep); + + if (status > 0) + return ER_INTERNAL_ERROR; + else if (status < 0) + return status; + + // Derived table projection and filter optimization. + derivedTableOptimization(csep); + + return 0; + } + + int cp_get_table_plan(THD * thd, SCSEP & csep, cal_table_info & ti) + { + gp_walk_info* gwi = ti.condInfo; + + if (!gwi) + gwi = new gp_walk_info(); + + gwi->thd = thd; + LEX* lex = thd->lex; + idbassert(lex != 0); + uint32_t sessionID = csep->sessionID(); + gwi->sessionid = sessionID; + TABLE* table = ti.msTablePtr; + boost::shared_ptr csc = CalpontSystemCatalog::makeCalpontSystemCatalog(sessionID); + csc->identity(CalpontSystemCatalog::FE); + + // get all columns that mysql needs to fetch + MY_BITMAP* read_set = table->read_set; + Field** f_ptr, *field; + gwi->columnMap.clear(); + + for (f_ptr = table->field ; (field = *f_ptr) ; f_ptr++) + { + if (bitmap_is_set(read_set, field->field_index)) + { + SimpleColumn* sc = new SimpleColumn(table->s->db.str, table->s->table_name.str, field->field_name, sessionID); + string alias(table->alias.c_ptr()); + sc->tableAlias(lower(alias)); + assert (sc); + boost::shared_ptr spsc(sc); + gwi->returnedCols.push_back(spsc); + gwi->columnMap.insert(CalpontSelectExecutionPlan::ColumnMap::value_type(string(field->field_name), spsc)); + } + } + + if (gwi->columnMap.empty()) + { + CalpontSystemCatalog::TableName tn = make_table(table->s->db.str, table->s->table_name.str); + CalpontSystemCatalog::TableAliasName tan = make_aliastable(table->s->db.str, table->s->table_name.str, table->alias.c_ptr()); + SimpleColumn* sc = getSmallestColumn(csc, tn, tan, table, *gwi); + SRCP srcp(sc); + gwi->columnMap.insert(CalpontSelectExecutionPlan::ColumnMap::value_type(sc->columnName(), srcp)); + gwi->returnedCols.push_back(srcp); + } + + // get filter + if (ti.condInfo) + { + gp_walk_info* gwi = ti.condInfo; + ParseTree* filters = 0; + ParseTree* ptp = 0; + ParseTree* rhs = 0; + + while (!gwi->ptWorkStack.empty()) + { + filters = gwi->ptWorkStack.top(); + gwi->ptWorkStack.pop(); + SimpleFilter* sf = dynamic_cast(filters->data()); + + if (sf && sf->op()->data() == "noop") + { + delete filters; + filters = 0; + + if (gwi->ptWorkStack.empty()) + break; + + continue; + } + + if (gwi->ptWorkStack.empty()) + break; + + ptp = new ParseTree(new LogicOperator("and")); + ptp->left(filters); + rhs = gwi->ptWorkStack.top(); + gwi->ptWorkStack.pop(); + ptp->right(rhs); + gwi->ptWorkStack.push(ptp); + } + + csep->filters(filters); + } + + csep->returnedCols(gwi->returnedCols); + csep->columnMap(gwi->columnMap); + CalpontSelectExecutionPlan::TableList tblist; + tblist.push_back(make_aliastable(table->s->db.str, table->s->table_name.str, table->alias.c_ptr())); + csep->tableList(tblist); + + // @bug 3321. Set max number of blocks in a dictionary file to be scanned for filtering + csep->stringScanThreshold(gwi->thd->variables.infinidb_string_scan_threshold); + + return 0; + } + + int cp_get_group_plan(THD * thd, SCSEP & csep, cal_impl_if::cal_group_info & gi) + { + LEX* lex = thd->lex; + idbassert(lex != 0); + + SELECT_LEX select_lex = lex->select_lex; + gp_walk_info gwi; + gwi.thd = thd; + int status = getGroupPlan(gwi, select_lex, csep, gi); + + if (status > 0) + return ER_INTERNAL_ERROR; + else if (status < 0) + return status; + + return 0; + } + + /*@brief buildConstColFromFilter- change SimpleColumn into ConstColumn*/ + /*********************************************************** + * DESCRIPTION: + * Server could optimize out fields from GROUP BY list, when certain + * 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. + * PARAMETERS: + * originalSC SimpleColumn* removed field + * gwi main strucutre + * gi auxilary group_by handler structure + * RETURNS + * ConstantColumn* if originalSC equals with cond_pushed columns. + * NULL otherwise + ***********************************************************/ + ConstantColumn* buildConstColFromFilter(SimpleColumn * originalSC, + gp_walk_info & gwi, cal_group_info & gi) + { + execplan::SimpleColumn* simpleCol; + execplan::ConstantColumn* constCol; + execplan::SOP op; + execplan::SimpleFilter* simpFilter; + execplan::ConstantColumn* result = NULL; + std::vector::iterator ptIt = gi.pushedPts.begin(); + + for (; ptIt != gi.pushedPts.end(); ptIt++) + { + simpFilter = dynamic_cast((*ptIt)->data()); + + if (simpFilter == NULL) + continue; + + simpleCol = dynamic_cast(simpFilter->lhs()); + constCol = dynamic_cast(simpFilter->rhs()); + + if (simpleCol == NULL || constCol == NULL) + continue; + + op = simpFilter->op(); + + if ( originalSC->sameColumn(dynamic_cast(simpleCol)) + && op.get()->op() == OP_EQ && constCol) + { +#ifdef DEBUG_WALK_COND + cerr << "buildConstColFromFilter() replaced " << endl; + cerr << simpleCol->toString() << endl; + cerr << " with " << endl; + cerr << constCol << endl; +#endif + result = constCol; + } + } + + return result; + } + + int getGroupPlan(gp_walk_info & gwi, SELECT_LEX & select_lex, SCSEP & csep, cal_group_info & gi, bool isUnion) + { +#ifdef DEBUG_WALK_COND + cerr << "getGroupPlan()" << endl; +#endif + + // rollup is currently not supported + if (select_lex.olap == ROLLUP_TYPE) + { + gwi.fatalParseError = true; + gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_ROLLUP_NOT_SUPPORT); + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + + gwi.internalDecimalScale = (gwi.thd->variables.infinidb_use_decimal_scale ? gwi.thd->variables.infinidb_decimal_scale : -1); + gwi.subSelectType = csep->subType(); + + JOIN* join = select_lex.join; + Item_cond* icp = 0; + + if ( gi.groupByWhere ) + icp = reinterpret_cast(gi.groupByWhere); + + uint32_t sessionID = csep->sessionID(); + gwi.sessionid = sessionID; + boost::shared_ptr csc = CalpontSystemCatalog::makeCalpontSystemCatalog(sessionID); + csc->identity(CalpontSystemCatalog::FE); + gwi.csc = csc; + + // @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 || gwi.thd->variables.infinidb_ordered_only) + csep->overrideLargeSideEstimate(true); + + // @bug 5741. Set a flag when in Local PM only query mode + csep->localQuery(gwi.thd->variables.infinidb_local_query); + + // @bug 3321. Set max number of blocks in a dictionary file to be scanned for filtering + csep->stringScanThreshold(gwi.thd->variables.infinidb_string_scan_threshold); + + csep->stringTableThreshold(gwi.thd->variables.infinidb_stringtable_threshold); + + csep->djsSmallSideLimit(gwi.thd->variables.infinidb_diskjoin_smallsidelimit * 1024ULL * 1024); + csep->djsLargeSideLimit(gwi.thd->variables.infinidb_diskjoin_largesidelimit * 1024ULL * 1024); + csep->djsPartitionSize(gwi.thd->variables.infinidb_diskjoin_bucketsize * 1024ULL * 1024); + + if (gwi.thd->variables.infinidb_um_mem_limit == 0) + csep->umMemLimit(numeric_limits::max()); + else + csep->umMemLimit(gwi.thd->variables.infinidb_um_mem_limit * 1024ULL * 1024); + + // populate table map and trigger syscolumn cache for all the tables (@bug 1637). + // all tables on FROM list must have at least one col in colmap + TABLE_LIST* table_ptr = gi.groupByTables; + CalpontSelectExecutionPlan::SelectList derivedTbList; + +// DEBUG +#ifdef DEBUG_WALK_COND + List_iterator sj_list_it(select_lex.sj_nests); + TABLE_LIST* sj_nest; + + while ((sj_nest = sj_list_it++)) + { + cerr << sj_nest->db << "." << sj_nest->table_name << endl; + } + +#endif + + // @bug 1796. Remember table order on the FROM list. + gwi.clauseType = FROM; + + try + { + for (; table_ptr; table_ptr = table_ptr->next_local) + { + // mysql put vtable here for from sub. we ignore it + //if (string(table_ptr->table_name).find("$vtable") != string::npos) + // continue; + + // Until we handle recursive cte: + // Checking here ensures we catch all with clauses in the query. + if (table_ptr->is_recursive_with_table()) + { + gwi.fatalParseError = true; + gwi.parseErrorText = "Recursive CTE"; + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + + string viewName = getViewName(table_ptr); + + // @todo process from subquery + if (table_ptr->derived) + { + String str; + (table_ptr->derived->first_select())->print(gwi.thd, &str, QT_INFINIDB_DERIVED); + + SELECT_LEX* select_cursor = table_ptr->derived->first_select(); + FromSubQuery fromSub(gwi, select_cursor); + string alias(table_ptr->alias); + fromSub.alias(lower(alias)); + + CalpontSystemCatalog::TableAliasName tn = make_aliasview("", "", alias, viewName); + // @bug 3852. check return execplan + SCSEP plan = fromSub.transform(); + + if (!plan) + { + setError(gwi.thd, ER_INTERNAL_ERROR, fromSub.gwip().parseErrorText, gwi); + CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); + return ER_INTERNAL_ERROR; + } + + gwi.derivedTbList.push_back(plan); + 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 + } + else if (table_ptr->view) + { + View* view = new View(table_ptr->view->select_lex, &gwi); + CalpontSystemCatalog::TableAliasName tn = make_aliastable(table_ptr->db, table_ptr->table_name, table_ptr->alias); + view->viewName(tn); + gwi.viewList.push_back(view); + view->transform(); + } + else + { + // check foreign engine tables + bool infiniDB = (table_ptr->table ? isInfiniDB(table_ptr->table) : true); + + // trigger system catalog cache + if (infiniDB) + csc->columnRIDs(make_table(table_ptr->db, table_ptr->table_name), true); + + string table_name = table_ptr->table_name; + + // @bug5523 + if (table_ptr->db && strcmp(table_ptr->db, "information_schema") == 0) + table_name = (table_ptr->schema_table_name ? table_ptr->schema_table_name : table_ptr->alias); + + CalpontSystemCatalog::TableAliasName tn = make_aliasview(table_ptr->db, table_name, table_ptr->alias, viewName, infiniDB); + gwi.tbList.push_back(tn); + CalpontSystemCatalog::TableAliasName tan = make_aliastable(table_ptr->db, table_name, table_ptr->alias, infiniDB); + gwi.tableMap[tan] = make_pair(0, table_ptr); +#ifdef DEBUG_WALK_COND + cerr << tn << endl; +#endif + } + } + + if (gwi.fatalParseError) + { + setError(gwi.thd, ER_INTERNAL_ERROR, gwi.parseErrorText, gwi); + return ER_INTERNAL_ERROR; + } + } + catch (IDBExcept& ie) + { + setError(gwi.thd, ER_INTERNAL_ERROR, ie.what(), gwi); + CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); + // @bug 3852. set error status for gwi. + gwi.fatalParseError = true; + gwi.parseErrorText = ie.what(); + return ER_INTERNAL_ERROR; + } + catch (...) + { + string emsg = IDBErrorInfo::instance()->errorMsg(ERR_LOST_CONN_EXEMGR); + // @bug3852 set error status for gwi. + gwi.fatalParseError = true; + gwi.parseErrorText = emsg; + setError(gwi.thd, ER_INTERNAL_ERROR, emsg, gwi); + CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); + return ER_INTERNAL_ERROR; + } + + csep->tableList(gwi.tbList); + + bool unionSel = false; + + gwi.clauseType = WHERE; + + + if (icp) + { + // MCOL-1052 The condition could be useless. + // 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) + { + icp->fix_fields(gwi.thd, (Item**)&icp); + } + +//#endif + gwi.fatalParseError = false; +#ifdef DEBUG_WALK_COND + cerr << "------------------ WHERE -----------------------" << endl; + icp->traverse_cond(debug_walk, &gwi, Item::POSTFIX); + cerr << "------------------------------------------------\n" << endl; +#endif + + icp->traverse_cond(gp_walk, &gwi, Item::POSTFIX); + + if (gwi.fatalParseError) + { + // if this is dervied table process phase, mysql may have not developed the plan + // completely. Do not error and eventually mysql will call JOIN::exec() again. + // related to bug 2922. Need to find a way to skip calling rnd_init for derived table + // processing. + if (gwi.thd->derived_tables_processing) + { + gwi.thd->infinidb_vtable.isUnion = false; + gwi.thd->infinidb_vtable.isUpdateWithDerive = true; + return -1; + } + + setError(gwi.thd, ER_INTERNAL_ERROR, gwi.parseErrorText, gwi); + return ER_INTERNAL_ERROR; + } + } + else if (join && join->zero_result_cause) + { + gwi.rcWorkStack.push(new ConstantColumn((int64_t)0, ConstantColumn::NUM)); + } + + uint32_t failed = buildOuterJoin(gwi, select_lex); + + if (failed) return failed; + + // @bug5764. build outer join for view, make sure outerjoin filter is appended + // to the end of the filter list. + for (uint i = 0; i < gwi.viewList.size(); i++) + { + failed = gwi.viewList[i]->processOuterJoin(gwi); + + if (failed) + break; + } + + if (failed != 0) + return failed; + + ParseTree* filters = NULL; + ParseTree* ptp = NULL; + ParseTree* lhs = NULL; + + // @bug 2932. for "select * from region where r_name" case. if icp not null and + // ptWorkStack empty, the item is in rcWorkStack. + // MySQL 5.6 (MariaDB?). when icp is null and zero_result_cause is set, a constant 0 + // is pushed to rcWorkStack. + if (/*icp && */gwi.ptWorkStack.empty() && !gwi.rcWorkStack.empty()) + { + filters = new ParseTree(gwi.rcWorkStack.top()); + gwi.rcWorkStack.pop(); + } + + while (!gwi.ptWorkStack.empty()) + { + filters = gwi.ptWorkStack.top(); + gwi.ptWorkStack.pop(); + + if (gwi.ptWorkStack.empty()) + break; + + ptp = new ParseTree(new LogicOperator("and")); + //ptp->left(filters); + ptp->right(filters); + lhs = gwi.ptWorkStack.top(); + gwi.ptWorkStack.pop(); + //ptp->right(rhs); + ptp->left(lhs); + gwi.ptWorkStack.push(ptp); + } + + if (filters) + { + csep->filters(filters); +#ifdef DEBUG_WALK_COND + filters->drawTree("/tmp/filter1.dot"); +#endif + } + + gwi.clauseType = SELECT; +#ifdef DEBUG_WALK_COND + { + cerr << "------------------- SELECT --------------------" << endl; + List_iterator_fast it(*gi.groupByFields); + Item* item; + + while ((item = it++)) + { + debug_walk(item, 0); + } + + cerr << "-----------------------------------------------\n" << endl; + } +#endif + + // populate returnedcolumnlist and columnmap + 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. + clearStacks(gwi); + + // indicate the starting pos of scalar returned column, because some join column + // has been inserted to the returned column list. + if (gwi.subQuery) + { + ScalarSub* scalar = dynamic_cast(gwi.subQuery); + + if (scalar) + scalar->returnedColPos(gwi.additionalRetCols.size()); + } + + CalpontSelectExecutionPlan::SelectList selectSubList; + + while ((item = it++)) + { + string itemAlias = (item->name ? item->name : ""); + + // @bug 5916. Need to keep checking until getting concret item in case + // of nested view. + while (item->type() == Item::REF_ITEM) + { + Item_ref* ref = (Item_ref*)item; + item = (*(ref->ref)); + } + + Item::Type itype = item->type(); + + switch (itype) + { + case Item::FIELD_ITEM: + { + Item_field* ifp = (Item_field*)item; + SimpleColumn* sc = NULL; + ConstantColumn* constCol = NULL; + + if (ifp->field_name && string(ifp->field_name) == "*") + { + collectAllCols(gwi, ifp); + break; + } + + sc = buildSimpleColumn(ifp, gwi); + + if (sc) + { + constCol = buildConstColFromFilter(sc, gwi, gi); + 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); + 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 + { + if (!itemAlias.empty()) + sc->alias(itemAlias); + + sel_cols_in_create += fullname + " `" + escapeBackTick(sc->alias().c_str()) + "`"; + } + + if (ifp->is_autogenerated_name) + gwi.selectCols.push_back("`" + escapeBackTick(fullname.c_str()) + "`" + " `" + + escapeBackTick(itemAlias.empty() ? ifp->name : itemAlias.c_str()) + "`"); + else + gwi.selectCols.push_back("`" + escapeBackTick((itemAlias.empty() ? ifp->name : itemAlias.c_str())) + "`"); + + // MCOL-1052 Replace SimpleColumn with ConstantColumn, + // since it must have a single value only. + if (constCol) + { + gwi.returnedCols.push_back(spcc); + gwi.columnMap.insert(CalpontSelectExecutionPlan::ColumnMap::value_type(string(ifp->field_name), spcc)); + } + else + { + gwi.returnedCols.push_back(spsc); + gwi.columnMap.insert(CalpontSelectExecutionPlan::ColumnMap::value_type(string(ifp->field_name), spsc)); + } + + TABLE_LIST* tmp = 0; + + if (ifp->cached_table) + tmp = ifp->cached_table; + + gwi.tableMap[make_aliastable(sc->schemaName(), sc->tableName(), sc->tableAlias(), sc->isInfiniDB())] = + make_pair(1, tmp); + } + else + { + setError(gwi.thd, ER_INTERNAL_ERROR, gwi.parseErrorText, gwi); + delete sc; + return ER_INTERNAL_ERROR; + } + + break; + } + + //aggregate column + case Item::SUM_FUNC_ITEM: + { + ReturnedColumn* ac = buildAggregateColumn(item, gwi); + + if (gwi.fatalParseError) + { + // e.g., non-support ref column + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); + delete ac; + return ER_CHECK_NOT_IMPLEMENTED; + } + + // add this agg col to returnedColumnList + boost::shared_ptr spac(ac); + gwi.returnedCols.push_back(spac); + // This item will be used in HAVING later. + Item_func_or_sum* isfp = reinterpret_cast(item); + + if ( ! isfp->name_length ) + { + gwi.havingAggColsItems.push_back(item); + } + + gwi.selectCols.push_back('`' + escapeBackTick(spac->alias().c_str()) + '`'); + String str(256); + item->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()) + " `" + escapeBackTick(spac->alias().c_str()) + "`"; + break; + } + + case Item::FUNC_ITEM: + { + Item_func* ifp = reinterpret_cast(item); + + // @bug4383. error out non-support stored function + if (ifp->functype() == Item_func::FUNC_SP) + { + gwi.fatalParseError = true; + gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_SP_FUNCTION_NOT_SUPPORT); + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + + if (string(ifp->func_name()) == "xor") + { + gwi.fatalParseError = true; + gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_FILTER_COND_EXP); + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + + uint16_t parseInfo = 0; + vector tmpVec; + bool hasNonSupportItem = false; + parse_item(ifp, tmpVec, hasNonSupportItem, parseInfo); + + if (ifp->has_subquery() || + string(ifp->func_name()) == string("") || + ifp->functype() == Item_func::NOT_ALL_FUNC || + parseInfo & SUB_BIT) + { + gwi.fatalParseError = true; + gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_SELECT_SUB); + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + + ReturnedColumn* rc = buildFunctionColumn(ifp, gwi, hasNonSupportItem); + SRCP srcp(rc); + + if (rc) + { + 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); + + if (ifp->name) + srcp->alias(ifp->name); + + 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) + "`"); + } + + break; + } + + //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 + "`"; + gwi.selectCols.push_back("`" + escapeBackTick(ifp->name) + "`"); + } + } + else // InfiniDB Non support functions still go through post process for now + { + hasNonSupportItem = false; + uint32_t before_size = funcFieldVec.size(); + parse_item(ifp, funcFieldVec, hasNonSupportItem, parseInfo); + uint32_t after_size = funcFieldVec.size(); + + // group by func and func in subquery can not be post processed + // @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) && + !hasNonSupportItem && (after_size - before_size) == 0 && + !(parseInfo & AGG_BIT) && !(parseInfo & SUB_BIT) && + string(ifp->func_name()) != "set_user_var") + { + String val, *str = ifp->val_str(&val); + string valStr; + + if (str) + valStr.assign(str->ptr(), str->length()); + + ConstantColumn* cc = NULL; + + if (!str) + { + cc = new ConstantColumn("", ConstantColumn::NULLDATA); + } + else if (ifp->result_type() == STRING_RESULT) + { + cc = new ConstantColumn(valStr, ConstantColumn::LITERAL); + } + else if (ifp->result_type() == DECIMAL_RESULT) + { + cc = buildDecimalColumn(ifp, gwi); + } + else + { + cc = new ConstantColumn(valStr, ConstantColumn::NUM); + cc->resultType(colType_MysqlToIDB(item)); + } + + SRCP srcp(cc); + + if (ifp->name) + cc->alias(ifp->name); + + gwi.returnedCols.push_back(srcp); + + // clear the error set by buildFunctionColumn + gwi.fatalParseError = false; + gwi.parseErrorText = ""; + break; + } + else if (hasNonSupportItem || parseInfo & AGG_BIT || parseInfo & SUB_BIT || + (gwi.fatalParseError && gwi.subQuery)) + { + if (gwi.parseErrorText.empty()) + { + 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; + } + else if ( gwi.subQuery && (isPredicateFunction(ifp, &gwi) || ifp->type() == Item::COND_ITEM )) + { + gwi.fatalParseError = true; + gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_FILTER_COND_EXP); + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + + //@Bug 3030 Add error check for dml statement + if ( ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE ) || ((gwi.thd->lex)->sql_command == SQLCOM_DELETE ) || ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE_MULTI ) || ((gwi.thd->lex)->sql_command == SQLCOM_DELETE_MULTI ) ) + { + if ( after_size - before_size != 0 ) + { + gwi.parseErrorText = ifp->func_name(); + 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); + gwi.selectCols.push_back(string(funcStr.c_ptr()) + " `" + escapeBackTick(ifp->name) + "`"); + // clear the error set by buildFunctionColumn + gwi.fatalParseError = false; + gwi.parseErrorText = ""; + } + } + + break; + } + + case Item::INT_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 + { + // do not push the dummy column (mysql added) to returnedCol + if (item->name && string(item->name) == "Not_used") + continue; + + // @bug3509. Constant column is sent to ExeMgr now. + SRCP srcp(buildReturnedColumn(item, gwi, gwi.fatalParseError)); + + if (item->name) + srcp->alias(item->name); + + gwi.returnedCols.push_back(srcp); + + 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 += ", "; + + sel_cols_in_create += oss.str(); + gwi.selectCols.push_back(oss.str()); + } + + 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) + srcp->alias(item->name); + + 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) + srcp->alias(item->name); + + 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; + } + + case Item::NULL_ITEM: + { + /*if ( ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE ) || ((gwi.thd->lex)->sql_command == SQLCOM_DELETE ) || ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE_MULTI ) || ((gwi.thd->lex)->sql_command == SQLCOM_DELETE_MULTI ) ) + { } + else + { + SRCP srcp(buildReturnedColumn(item, gwi, gwi.fatalParseError)); + gwi.returnedCols.push_back(srcp); + + if (item->name) + srcp->alias(item->name); + + 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"); + }*/ + + break; + } + + case Item::SUBSELECT_ITEM: + { + Item_subselect* sub = (Item_subselect*)item; + + if (sub->substype() != Item_subselect::SINGLEROW_SUBS) + { + gwi.fatalParseError = true; + gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_SELECT_SUB); + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + +#ifdef DEBUG_WALK_COND + cerr << "SELECT clause SUBSELECT Item: " << sub->substype() << endl; + JOIN* join = sub->get_select_lex()->join; + + if (join) + { + Item_cond* cond = reinterpret_cast(join->conds); + + if (cond) + cond->traverse_cond(debug_walk, &gwi, Item::POSTFIX); + } + + cerr << "Finish SELECT clause subselect item traversing" << endl; +#endif + SelectSubQuery* selectSub = new SelectSubQuery(gwi, sub); + //selectSub->gwip(&gwi); + SCSEP ssub = selectSub->transform(); + + if (!ssub || gwi.fatalParseError) + { + if (gwi.parseErrorText.empty()) + gwi.parseErrorText = "Unsupported Item in SELECT subquery."; + + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + + selectSubList.push_back(ssub); + SimpleColumn* rc = new SimpleColumn(); + rc->colSource(rc->colSource() | SELECT_SUB); + + if (sub->get_select_lex()->get_table_list()) + rc->viewName(lower(getViewName(sub->get_select_lex()->get_table_list()))); + + if (sub->name) + rc->alias(sub->name); + + 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) + { + sel_cols_in_create += "`" + escapeBackTick(sub->name) + "`"; + gwi.selectCols.push_back(sub->name); + } + else + { + sel_cols_in_create += "`" + escapeBackTick(str.c_ptr()) + "`"; + gwi.selectCols.push_back("`" + escapeBackTick(str.c_ptr()) + "`"); + } + + break; + } + + case Item::COND_ITEM: + { + gwi.fatalParseError = true; + gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_FILTER_COND_EXP); + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + + case Item::EXPR_CACHE_ITEM: + { + printf("EXPR_CACHE_ITEM in getSelectPlan\n"); + gwi.fatalParseError = true; + gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_UNKNOWN_COL); + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + + case Item::WINDOW_FUNC_ITEM: + { + SRCP srcp(buildWindowFunctionColumn(item, gwi, gwi.fatalParseError)); + + if (!srcp || gwi.fatalParseError) + { + if (gwi.parseErrorText.empty()) + gwi.parseErrorText = "Unsupported Item in SELECT subquery."; + + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + + gwi.returnedCols.push_back(srcp); + break; + } + + default: + { + break; + } + } + } + + // @bug4388 normalize the project coltypes for union main select list + if (!csep->unionVec().empty()) + { + for (uint32_t i = 0; i < gwi.returnedCols.size(); i++) + { + vector coltypes; + + for (uint32_t j = 0; j < csep->unionVec().size(); j++) + { + coltypes.push_back( + dynamic_cast(csep->unionVec()[j].get())->returnedCols()[i]->resultType()); + + // @bug5976. set hasAggregate true for the main column if + // one corresponding union column has aggregate + if (dynamic_cast(csep->unionVec()[j].get())->returnedCols()[i]->hasAggregate()) + gwi.returnedCols[i]->hasAggregate(true); + } + + gwi.returnedCols[i]->resultType(dataconvert::DataConvert::convertUnionColType(coltypes)); + } + } + + // Having clause handling + gwi.clauseType = HAVING; + clearStacks(gwi); + ParseTree* havingFilter = 0; + // clear fatalParseError that may be left from post process functions + gwi.fatalParseError = false; + gwi.parseErrorText = ""; + + if (gi.groupByHaving != 0) + { + Item_cond* having = reinterpret_cast(gi.groupByHaving); +#ifdef DEBUG_WALK_COND + cerr << "------------------- HAVING ---------------------" << endl; + having->traverse_cond(debug_walk, &gwi, Item::POSTFIX); + cerr << "------------------------------------------------\n" << endl; +#endif + having->traverse_cond(gp_walk, &gwi, Item::POSTFIX); + + if (gwi.fatalParseError) + { + setError(gwi.thd, ER_INTERNAL_ERROR, gwi.parseErrorText, gwi); + return ER_INTERNAL_ERROR; + } + + ParseTree* ptp = 0; + ParseTree* rhs = 0; + + // @bug 4215. some function filter will be in the rcWorkStack. + if (gwi.ptWorkStack.empty() && !gwi.rcWorkStack.empty()) + { + havingFilter = new ParseTree(gwi.rcWorkStack.top()); + gwi.rcWorkStack.pop(); + } + + while (!gwi.ptWorkStack.empty()) + { + havingFilter = gwi.ptWorkStack.top(); + gwi.ptWorkStack.pop(); + + if (gwi.ptWorkStack.empty()) + break; + + ptp = new ParseTree(new LogicOperator("and")); + ptp->left(havingFilter); + rhs = gwi.ptWorkStack.top(); + gwi.ptWorkStack.pop(); + ptp->right(rhs); + gwi.ptWorkStack.push(ptp); + } + } + + // for post process expressions on the select list + // error out post process for union and sub select unit + if (isUnion || gwi.subSelectType != CalpontSelectExecutionPlan::MAIN_SELECT) + { + if (funcFieldVec.size() != 0 && !gwi.fatalParseError) + { + string emsg("Fatal parse error in vtable mode: Unsupported Items in union or sub select unit"); + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, emsg); + return ER_CHECK_NOT_IMPLEMENTED; + } + } + + for (uint32_t i = 0; i < funcFieldVec.size(); i++) + { + SimpleColumn* sc = buildSimpleColumn(funcFieldVec[i], gwi); + + if (!sc || gwi.fatalParseError) + { + string emsg; + + if (gwi.parseErrorText.empty()) + { + emsg = "un-recognized column"; + + if (funcFieldVec[i]->name) + emsg += string(funcFieldVec[i]->name); + } + else + { + emsg = gwi.parseErrorText; + } + + setError(gwi.thd, ER_INTERNAL_ERROR, emsg, gwi); + return ER_INTERNAL_ERROR; + } + + String str; + funcFieldVec[i]->print(&str, QT_INFINIDB_NO_QUOTE); + sc->alias(string(str.c_ptr())); + //sc->tableAlias(funcFieldVec[i]->table_name); + sc->tableAlias(sc->tableAlias()); + SRCP srcp(sc); + uint32_t j = 0; + + for (; j < gwi.returnedCols.size(); j++) + { + if (sc->sameColumn(gwi.returnedCols[j].get())) + { + SimpleColumn* field = dynamic_cast(gwi.returnedCols[j].get()); + + if (field && field->alias() == sc->alias()) + break; + } + } + + if (j == gwi.returnedCols.size()) + { + gwi.returnedCols.push_back(srcp); + gwi.columnMap.insert(CalpontSelectExecutionPlan::ColumnMap::value_type(string(funcFieldVec[i]->field_name), 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) + { + gwi.clauseType = GROUP_BY; + Item* nonSupportItem = NULL; + ORDER* groupcol = reinterpret_cast(gi.groupByGroup); + + // check if window functions are in order by. InfiniDB process order by list if + // window functions are involved, either in order by or projection. + bool hasWindowFunc = gwi.hasWindowFunc; + gwi.hasWindowFunc = false; + + for (; groupcol; groupcol = groupcol->next) + { + if ((*(groupcol->item))->type() == Item::WINDOW_FUNC_ITEM) + gwi.hasWindowFunc = true; + } + + if (gwi.hasWindowFunc) + { + gwi.fatalParseError = true; + gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_WF_NOT_ALLOWED, "GROUP BY clause"); + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + + gwi.hasWindowFunc = hasWindowFunc; + groupcol = reinterpret_cast(gi.groupByGroup); + + for (; groupcol; groupcol = groupcol->next) + { + Item* groupItem = *(groupcol->item); + + // @bug5993. Could be nested ref. + while (groupItem->type() == Item::REF_ITEM) + groupItem = (*((Item_ref*)groupItem)->ref); + + if (groupItem->type() == Item::FUNC_ITEM) + { + Item_func* ifp = (Item_func*)groupItem; + + // call buildFunctionColumn here mostly for finding out + // non-support column on GB list. Should be simplified. + ReturnedColumn* fc = buildFunctionColumn(ifp, gwi, gwi.fatalParseError); + + if (!fc || gwi.fatalParseError) + { + nonSupportItem = ifp; + break; + } + + if (groupcol->in_field_list && groupcol->counter_used) + { + delete fc; + fc = gwi.returnedCols[groupcol->counter - 1].get(); + SRCP srcp(fc->clone()); + + // check if no column parm + for (uint32_t i = 0; i < gwi.no_parm_func_list.size(); i++) + { + if (gwi.no_parm_func_list[i]->expressionId() == fc->expressionId()) + { + gwi.no_parm_func_list.push_back(dynamic_cast(srcp.get())); + break; + } + } + + srcp->orderPos(groupcol->counter - 1); + gwi.groupByCols.push_back(srcp); + continue; + } + else if (!groupItem->is_autogenerated_name) // alias + { + uint32_t i = 0; + + for (; i < gwi.returnedCols.size(); i++) + { + if (string(groupItem->name) == gwi.returnedCols[i]->alias()) + { + ReturnedColumn* rc = gwi.returnedCols[i]->clone(); + rc->orderPos(i); + gwi.groupByCols.push_back(SRCP(rc)); + delete fc; + break; + } + } + + if (i == gwi.returnedCols.size()) + { + nonSupportItem = groupItem; + break; + } + } + else + { + uint32_t i = 0; + + for (; i < gwi.returnedCols.size(); i++) + { + if (fc->operator==(gwi.returnedCols[i].get())) + { + ReturnedColumn* rc = gwi.returnedCols[i]->clone(); + rc->orderPos(i); + gwi.groupByCols.push_back(SRCP(rc)); + delete fc; + break; + } + } + + if (i == gwi.returnedCols.size()) + { + gwi.groupByCols.push_back(SRCP(fc)); + break; + } + } + } + else if (groupItem->type() == Item::FIELD_ITEM) + { + Item_field* ifp = (Item_field*)groupItem; + // this GB col could be an alias of F&E on the SELECT clause, not necessarily a field. + ReturnedColumn* rc = buildSimpleColumn(ifp, gwi); + SimpleColumn* sc = dynamic_cast(rc); + + for (uint32_t j = 0; j < gwi.returnedCols.size(); j++) + { + if (sc) + { + if (sc->sameColumn(gwi.returnedCols[j].get())) + { + sc->orderPos(j); + break; + } + else if (strcasecmp(sc->alias().c_str(), gwi.returnedCols[j]->alias().c_str()) == 0) + { + rc = gwi.returnedCols[j].get()->clone(); + rc->orderPos(j); + break; + } + } + else + { + if (ifp->name && string(ifp->name) == gwi.returnedCols[j].get()->alias()) + { + rc = gwi.returnedCols[j].get()->clone(); + rc->orderPos(j); + break; + } + } + } + + if (!rc) + { + nonSupportItem = ifp; + break; + } + + SRCP srcp(rc); + + // bug 3151 + AggregateColumn* ac = dynamic_cast(rc); + + if (ac) + { + nonSupportItem = ifp; + break; + } + + gwi.groupByCols.push_back(srcp); + gwi.columnMap.insert(CalpontSelectExecutionPlan::ColumnMap::value_type(string(ifp->field_name), srcp)); + } + // @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)) + { + ReturnedColumn* rc = 0; + + for (uint32_t j = 0; j < gwi.returnedCols.size(); j++) + { + if (groupItem->name && string(groupItem->name) == gwi.returnedCols[j].get()->alias()) + { + rc = gwi.returnedCols[j].get()->clone(); + rc->orderPos(j); + break; + } + } + + if (!rc) + { + nonSupportItem = groupItem; + break; + } + + gwi.groupByCols.push_back(SRCP(rc)); + } + else if ((*(groupcol->item))->type() == Item::SUBSELECT_ITEM) + { + if (!groupcol->in_field_list || !groupItem->name) + { + nonSupportItem = groupItem; + } + else + { + uint32_t i = 0; + + for (; i < gwi.returnedCols.size(); i++) + { + if (string(groupItem->name) == gwi.returnedCols[i]->alias()) + { + ReturnedColumn* rc = gwi.returnedCols[i]->clone(); + rc->orderPos(i); + gwi.groupByCols.push_back(SRCP(rc)); + break; + } + } + + if (i == gwi.returnedCols.size()) + { + nonSupportItem = groupItem; + } + } + } + // @bug 3761. + else if (groupcol->counter_used) + { + if (gwi.returnedCols.size() <= (uint32_t)(groupcol->counter - 1)) + { + nonSupportItem = groupItem; + } + else + { + gwi.groupByCols.push_back(SRCP(gwi.returnedCols[groupcol->counter - 1]->clone())); + } + } + else + { + nonSupportItem = groupItem; + } + + } + + // @bug 4756. Add internal groupby column for correlated join to the groupby list + if (gwi.aggOnSelect && !gwi.subGroupByCols.empty()) + gwi.groupByCols.insert(gwi.groupByCols.end(), gwi.subGroupByCols.begin(), gwi.subGroupByCols.end()); + + // this is window func on SELECT becuase ORDER BY has not been processed + if (!gwi.windowFuncList.empty() && !gwi.subGroupByCols.empty()) + { + for (uint32_t i = 0; i < gwi.windowFuncList.size(); i++) + { + if (gwi.windowFuncList[i]->hasWindowFunc()) + { + vector windowFunctions = gwi.windowFuncList[i]->windowfunctionColumnList(); + + for (uint32_t j = 0; j < windowFunctions.size(); j++) + windowFunctions[j]->addToPartition(gwi.subGroupByCols); + } + } + } + + if (nonSupportItem) + { + Message::Args args; + + if (nonSupportItem->name) + args.add("'" + string(nonSupportItem->name) + "'"); + else + args.add(""); + + gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_GROUP_BY, args); + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + } // GROUP processing ends here + + + if (gwi.thd->infinidb_vtable.vtable_state == THD::INFINIDB_CREATE_VTABLE) + { + 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()); + algorithm::to_lower(lower_create_query); + 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. + for (; ordercol; ordercol = ordercol->next) + { + if ((*(ordercol->item))->type() == Item::WINDOW_FUNC_ITEM) + gwi.hasWindowFunc = true; + } + + // re-visit the first of ordercol list + ordercol = reinterpret_cast(gi.groupByOrder); + + // 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) + for (; ordercol; ordercol = ordercol->next) { ReturnedColumn* rc = NULL; @@ -6990,11 +9382,64 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i else rc = buildReturnedColumn(ord_item, gwi, gwi.fatalParseError); + // Looking for a match for this item in GROUP BY list. + if ( rc && ord_item->type() == Item::FIELD_ITEM ) + { + execplan::CalpontSelectExecutionPlan::ReturnedColumnList::iterator iter = gwi.groupByCols.begin(); + + for ( ; iter != gwi.groupByCols.end(); iter++ ) + { + if ( rc->sameColumn((*iter).get()) ) + break; + } + + // MCOL-1052 Find and remove the optimized field + // from ORDER using cond_pushed filters. + if (buildConstColFromFilter( + dynamic_cast(rc), gwi, gi)) + { + break; + } + + // MCOL-1052 GROUP BY items list doesn't contain + // 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) + ostream << iip->field_name; + else + ostream << "unknown field"; + + ostream << "'"; + 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; + } + } + // @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. if (!rc || gwi.fatalParseError) { + gwi.fatalParseError = false; Item* item_ptr = ordercol->item_ptr; while (item_ptr->type() == Item::REF_ITEM) @@ -7003,6 +9448,17 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i rc = buildReturnedColumn(item_ptr, gwi, gwi.fatalParseError); } + // This ORDER BY item must be an agg function - + // the ordercol->item_ptr and exteded SELECT list + // must contain the corresponding item. + if (!rc) + { + Item* item_ptr = ordercol->item_ptr; + + if (item_ptr) + rc = buildReturnedColumn(item_ptr, gwi, gwi.fatalParseError); + } + if (!rc) { string emsg = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_ORDER_BY); @@ -7019,61 +9475,334 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i gwi.orderByCols.push_back(SRCP(rc)); } - } - else if (!isUnion) - { - vector fieldVec; - bool addToSel; - // the following order by is just for redo phase - if (!unionSel) + + // make sure columnmap, returnedcols and count(*) arg_list are not empty + TableMap::iterator tb_iter = gwi.tableMap.begin(); + + try { - for (; ordercol; ordercol = ordercol->next) + for (; tb_iter != gwi.tableMap.end(); tb_iter++) { - Item* ord_item = *(ordercol->item); + if ((*tb_iter).second.first == 1) continue; - // @bug5993. Could be nested ref. - while (ord_item->type() == Item::REF_ITEM) - ord_item = (*((Item_ref*)ord_item)->ref); + CalpontSystemCatalog::TableAliasName tan = (*tb_iter).first; + CalpontSystemCatalog::TableName tn = make_table((*tb_iter).first.schema, (*tb_iter).first.table); + SimpleColumn* sc = getSmallestColumn(csc, tn, tan, (*tb_iter).second.second->table, gwi); + SRCP srcp(sc); + gwi.columnMap.insert(CalpontSelectExecutionPlan::ColumnMap::value_type(sc->columnName(), srcp)); + (*tb_iter).second.first = 1; + } + } + catch (runtime_error& e) + { + setError(gwi.thd, ER_INTERNAL_ERROR, e.what(), gwi); + CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); + return ER_INTERNAL_ERROR; + } + catch (...) + { + string emsg = IDBErrorInfo::instance()->errorMsg(ERR_LOST_CONN_EXEMGR); + setError(gwi.thd, ER_INTERNAL_ERROR, emsg, gwi); + CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); + return ER_INTERNAL_ERROR; + } - // @bug 1706. re-construct the order by item one by one - //Item* ord_item = *(ordercol->item); - if (ord_cols.length() != 0) - ord_cols += ", "; + if (!gwi.count_asterisk_list.empty() || !gwi.no_parm_func_list.empty() || + gwi.returnedCols.empty()) + { + // get the smallest column from colmap + CalpontSelectExecutionPlan::ColumnMap::const_iterator iter; + int minColWidth = 0; + CalpontSystemCatalog::ColType ct; - addToSel = true; - string fullname; - - if (ordercol->in_field_list && ordercol->counter_used) + try + { + for (iter = gwi.columnMap.begin(); iter != gwi.columnMap.end(); ++iter) { - ostringstream oss; - oss << ordercol->counter; - ord_cols += oss.str(); + // should always not null + SimpleColumn* sc = dynamic_cast(iter->second.get()); - if (ordercol->direction != ORDER::ORDER_ASC) - ord_cols += " desc"; + if (sc && !(sc->joinInfo() & JOIN_CORRELATED)) + { + ct = csc->colType(sc->oid()); - continue; + if (minColWidth == 0) + { + minColWidth = ct.colWidth; + minSc = iter->second; + } + else if (ct.colWidth < minColWidth) + { + minColWidth = ct.colWidth; + minSc = iter->second; + } + } + } + } + catch (...) + { + string emsg = IDBErrorInfo::instance()->errorMsg(ERR_LOST_CONN_EXEMGR); + setError(gwi.thd, ER_INTERNAL_ERROR, emsg, gwi); + CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); + return ER_INTERNAL_ERROR; + } + + if (gwi.returnedCols.empty() && gwi.additionalRetCols.empty()) + gwi.returnedCols.push_back(minSc); + } + + 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(); } - else if (ord_item->type() == Item::FUNC_ITEM) + // 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 + + for (; table_ptr; table_ptr = table_ptr->next_local) { - // @bug 2621. order by alias - if (!ord_item->is_autogenerated_name && ord_item->name) - { - ord_cols += ord_item->name; + if (string(table_ptr->table_name).find("$vtable") != string::npos) continue; + + if (table_ptr->derived) + { + if (aliasSet.find(table_ptr->alias) != 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); + firstTb = false; + aliasSet.insert(table_ptr->alias); + } + else if (table_ptr->view) + { + if (aliasSet.find(table_ptr->alias) != aliasSet.end()) + continue; + + if (!firstTb) + create_query += ", "; + + create_query += string(table_ptr->db) + "." + string(table_ptr->table_name) + + string(" `") + escapeBackTick(table_ptr->alias) + string("`"); + aliasSet.insert(table_ptr->alias); + 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) + "_" + + string(table_ptr->alias)) != aliasSet.end()) + continue; + + if (!firstTb) + create_query += ", "; + + create_query += string(table_ptr->db) + "." + string(table_ptr->table_name) + string(" "); + create_query += string(" `") + + escapeBackTick(table_ptr->referencing_view->alias) + "_" + + escapeBackTick(table_ptr->alias) + string("`"); + aliasSet.insert(string(table_ptr->referencing_view->alias) + "_" + + string(table_ptr->alias)); + } + else + { + if (aliasSet.find(table_ptr->alias) != aliasSet.end()) + continue; + + if (!firstTb) + create_query += ", "; + + create_query += string(table_ptr->db) + "." + string(table_ptr->table_name) + string(" "); + create_query += string("`") + escapeBackTick(table_ptr->alias) + string("`"); + aliasSet.insert(table_ptr->alias); + } + + 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) + { + // 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 && 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) + fullname += string(field->field_name); + + 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, 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) + '`'; } - // 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) + else if (ord_item->name) { + // for union order by 1 case. For unknown reason, it doesn't show in_field_list + if (ord_item->type() == Item::INT_ITEM) + { + ord_cols += ord_item->name; + } + else if (ord_item->type() == Item::SUBSELECT_ITEM) + { + string emsg = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_ORDER_BY); + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, emsg, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + else + { + ord_cols += string(" `") + escapeBackTick(ord_item->name) + '`'; + } + } + else if (ord_item->type() == Item::FUNC_ITEM) + { + // @bug5636. check if this order by column is on the select list + ReturnedColumn* rc = buildFunctionColumn((Item_func*)(ord_item), gwi, gwi.fatalParseError); + for (uint32_t i = 0; i < gwi.returnedCols.size(); i++) { if (rc && rc->operator==(gwi.returnedCols[i].get())) @@ -7081,2857 +9810,110 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i 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; - } - } - } - else if (ord_item->type() == Item::SUBSELECT_ITEM) - { - string emsg = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_ORDER_BY); - 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; - - Item_sum* ifp = (Item_sum*)(*(ordercol->item)); - // @bug3477. add aggregate column to the select list of the create phase. - ac = buildAggregateColumn(ifp, gwi); - - if (!ac) - { - setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, - IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_ORDER_BY), gwi); - return ER_CHECK_NOT_IMPLEMENTED; - } - - // check if this order by column is on the select list - for (uint32_t i = 0; i < gwi.returnedCols.size(); i++) - { - AggregateColumn* ret = dynamic_cast(gwi.returnedCols[i].get()); - - 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"; - - continue; - } - } - else if (ord_item->name && ord_item->type() == Item::FIELD_ITEM) - { - 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++) - { - 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, 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) - { - gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_ORDERBY_NOT_IN_DISTINCT); - setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); - return ER_CHECK_NOT_IMPLEMENTED; - } - - bool hasNonSupportItem = false; - uint16_t parseInfo = 0; - parse_item(ord_item, fieldVec, hasNonSupportItem, parseInfo); - - if (hasNonSupportItem) - { - string emsg = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_ORDER_BY); - setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, emsg, gwi); - 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"; - } - } - - redo = (redo || fieldVec.size() != 0); - - // populate string to be added to the select list for order by - for (uint32_t i = 0; i < fieldVec.size(); i++) - { - SimpleColumn* sc = buildSimpleColumn(fieldVec[i], gwi); - - if (!sc) - { - string emsg = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_ORDER_BY); - setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, emsg, gwi); - return ER_CHECK_NOT_IMPLEMENTED; - } - - String str; - fieldVec[i]->print(&str, QT_INFINIDB_NO_QUOTE); - sc->alias(string(str.c_ptr())); - SRCP srcp(sc); - uint32_t j = 0; - - for (; j < gwi.returnedCols.size(); j++) - { - if (sc->sameColumn(gwi.returnedCols[j].get())) - { - SimpleColumn* field = dynamic_cast(gwi.returnedCols[j].get()); - - if (field && field->alias() == sc->alias()) - break; - } - } - - 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), srcp)); - TABLE_LIST* tmp = (fieldVec[i]->cached_table ? fieldVec[i]->cached_table : 0); - gwi.tableMap[make_aliastable(sc->schemaName(), sc->tableName(), sc->tableAlias(), sc->isInfiniDB())] = - make_pair(1, tmp); - } - } - } - - // make sure columnmap, returnedcols and count(*) arg_list are not empty - TableMap::iterator tb_iter = gwi.tableMap.begin(); - - try - { - for (; tb_iter != gwi.tableMap.end(); tb_iter++) - { - if ((*tb_iter).second.first == 1) continue; - - CalpontSystemCatalog::TableAliasName tan = (*tb_iter).first; - CalpontSystemCatalog::TableName tn = make_table((*tb_iter).first.schema, (*tb_iter).first.table); - SimpleColumn* sc = getSmallestColumn(csc, tn, tan, (*tb_iter).second.second->table, gwi); - SRCP srcp(sc); - gwi.columnMap.insert(CalpontSelectExecutionPlan::ColumnMap::value_type(sc->columnName(), srcp)); - (*tb_iter).second.first = 1; - } - } - catch (runtime_error& e) - { - setError(gwi.thd, ER_INTERNAL_ERROR, e.what(), gwi); - CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); - return ER_INTERNAL_ERROR; - } - catch (...) - { - string emsg = IDBErrorInfo::instance()->errorMsg(ERR_LOST_CONN_EXEMGR); - setError(gwi.thd, ER_INTERNAL_ERROR, emsg, gwi); - CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); - return ER_INTERNAL_ERROR; - } - - if (!gwi.count_asterisk_list.empty() || !gwi.no_parm_func_list.empty() || - gwi.returnedCols.empty()) - { - // get the smallest column from colmap - CalpontSelectExecutionPlan::ColumnMap::const_iterator iter; - int minColWidth = 0; - CalpontSystemCatalog::ColType ct; - - try - { - for (iter = gwi.columnMap.begin(); iter != gwi.columnMap.end(); ++iter) - { - // should always not null - SimpleColumn* sc = dynamic_cast(iter->second.get()); - - if (sc && !(sc->joinInfo() & JOIN_CORRELATED)) - { - ct = csc->colType(sc->oid()); - - if (minColWidth == 0) - { - minColWidth = ct.colWidth; - minSc = iter->second; - } - else if (ct.colWidth < minColWidth) - { - minColWidth = ct.colWidth; - minSc = iter->second; - } - } - } - } - catch (...) - { - string emsg = IDBErrorInfo::instance()->errorMsg(ERR_LOST_CONN_EXEMGR); - setError(gwi.thd, ER_INTERNAL_ERROR, emsg, gwi); - CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); - return ER_INTERNAL_ERROR; - } - - if (gwi.returnedCols.empty() && gwi.additionalRetCols.empty()) - gwi.returnedCols.push_back(minSc); - } - - 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).find("$vtable") != string::npos) - continue; - - if (table_ptr->derived) - { - if (aliasSet.find(table_ptr->alias) != 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); - firstTb = false; - aliasSet.insert(table_ptr->alias); - } - else if (table_ptr->view) - { - if (aliasSet.find(table_ptr->alias) != aliasSet.end()) - continue; - - if (!firstTb) - create_query += ", "; - - create_query += string(table_ptr->db) + "." + string(table_ptr->table_name) + - string(" `") + escapeBackTick(table_ptr->alias) + string("`"); - aliasSet.insert(table_ptr->alias); - 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) + "_" + - string(table_ptr->alias)) != aliasSet.end()) - continue; - - if (!firstTb) - create_query += ", "; - - create_query += string(table_ptr->db) + "." + string(table_ptr->table_name) + string(" "); - create_query += string(" `") + - escapeBackTick(table_ptr->referencing_view->alias) + "_" + - escapeBackTick(table_ptr->alias) + string("`"); - aliasSet.insert(string(table_ptr->referencing_view->alias) + "_" + - string(table_ptr->alias)); - } else { - if (aliasSet.find(table_ptr->alias) != aliasSet.end()) - continue; - - if (!firstTb) - create_query += ", "; - - create_query += string(table_ptr->db) + "." + string(table_ptr->table_name) + string(" "); - create_query += string("`") + escapeBackTick(table_ptr->alias) + string("`"); - aliasSet.insert(table_ptr->alias); - } - - 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 && 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) - fullname += string(field->field_name); - - 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, 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) + '`'; - } - - else if (ord_item->name) - { - // for union order by 1 case. For unknown reason, it doesn't show in_field_list - if (ord_item->type() == Item::INT_ITEM) - { - ord_cols += ord_item->name; - } - else if (ord_item->type() == Item::SUBSELECT_ITEM) - { - string emsg = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_ORDER_BY); - setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, emsg, gwi); - return ER_CHECK_NOT_IMPLEMENTED; - } - else - { - ord_cols += string(" `") + escapeBackTick(ord_item->name) + '`'; - } - } - else if (ord_item->type() == Item::FUNC_ITEM) - { - // @bug5636. check if this order by column is on the select list - ReturnedColumn* rc = buildFunctionColumn((Item_func*)(ord_item), gwi, gwi.fatalParseError); - - 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(); - break; - } - } - } - else - { - String str; - ord_item->print(&str, QT_INFINIDB_NO_QUOTE); - ord_cols += string(str.c_ptr()); - } - - if (ordercol->direction != ORDER::ORDER_ASC) - ord_cols += " desc"; - } - } - - if (ord_cols.length() > 0) // has order by - { - gwi.thd->infinidb_vtable.has_order_by = true; - csep->hasOrderBy(true); - ord_cols = " order by " + ord_cols; - select_query += ord_cols; - } - } - - if (unionSel || gwi.subSelectType != CalpontSelectExecutionPlan::MAIN_SELECT) - { - if (select_lex.master_unit()->global_parameters()->explicit_limit) - { - if (select_lex.master_unit()->global_parameters()->offset_limit) - { - Item_int* offset = (Item_int*)select_lex.master_unit()->global_parameters()->offset_limit; - csep->limitStart(offset->val_int()); - } - - if (select_lex.master_unit()->global_parameters()->select_limit) - { - Item_int* select = (Item_int*)select_lex.master_unit()->global_parameters()->select_limit; - 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(); - } - } - } - else if (isUnion && select_lex.explicit_limit) - { - if (select_lex.braces) - { - if (select_lex.offset_limit) - csep->limitStart(((Item_int*)select_lex.offset_limit)->val_int()); - - if (select_lex.select_limit) - csep->limitNum(((Item_int*)select_lex.select_limit)->val_int()); - } - } - else if (select_lex.explicit_limit) - { - uint32_t limitOffset = 0; - uint32_t limitNum = std::numeric_limits::max(); - - if (join) - { -#if MYSQL_VERSION_ID >= 50172 - - // @bug5729. After upgrade, join->unit sometimes is uninitialized pointer - // (not null though) and will cause seg fault. Prefer checking - // 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->select_limit && - join->select_lex->select_limit->fixed) - { - limitOffset = join->select_lex->offset_limit->val_int(); - limitNum = join->select_lex->select_limit->val_int(); - } - - else if (join->unit) - { - limitOffset = join->unit->offset_limit_cnt; - limitNum = join->unit->select_limit_cnt - limitOffset; - } - -#else - limitOffset = (join->unit)->offset_limit_cnt; - limitNum = (join->unit)->select_limit_cnt - (join->unit)->offset_limit_cnt; -#endif - } - else - { - if (select_lex.master_unit()->global_parameters()->offset_limit) - { - Item_int* offset = (Item_int*)select_lex.master_unit()->global_parameters()->offset_limit; - limitOffset = offset->val_int(); - } - - if (select_lex.master_unit()->global_parameters()->select_limit) - { - Item_int* select = (Item_int*)select_lex.master_unit()->global_parameters()->select_limit; - limitNum = select->val_int(); - } - } - - // 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()) - { - csep->limitStart(limitOffset); - csep->limitNum(limitNum); - } - else - { - ostringstream limit; - limit << " limit " << limitOffset << ", " << limitNum; - select_query += limit.str(); - } - } - - 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()) - { - gwi.fatalParseError = true; - gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_LIMIT_SUB); - setError(gwi.thd, ER_INTERNAL_ERROR, gwi.parseErrorText, gwi); - return ER_CHECK_NOT_IMPLEMENTED; - } - } - - if (/*join->select_options*/select_lex.options & SELECT_DISTINCT) - csep->distinct(true); - - // add the smallest column to count(*) parm. - // select constant in subquery case - std::vector::iterator coliter; - - if (!minSc) - { - if (!gwi.returnedCols.empty()) - minSc = gwi.returnedCols[0]; - else if (!gwi.additionalRetCols.empty()) - minSc = gwi.additionalRetCols[0]; - } - - // @bug3523, count(*) on subquery always pick column[0]. - SimpleColumn* sc = dynamic_cast(minSc.get()); - - if (sc && sc->schemaName().empty()) - { - if (gwi.derivedTbList.size() >= 1) - { - SimpleColumn* sc1 = new SimpleColumn(); - sc1->columnName(sc->columnName()); - sc1->tableName(sc->tableName()); - sc1->tableAlias(sc->tableAlias()); - sc1->viewName(lower(sc->viewName())); - sc1->colPosition(0); - minSc.reset(sc1); - } - } - - for (coliter = gwi.count_asterisk_list.begin(); coliter != gwi.count_asterisk_list.end(); ++coliter) - { - // @bug5977 @note should never throw this, but checking just in case. - // When ExeMgr fix is ready, this should not error out... - if (dynamic_cast(minSc.get())) - { - gwi.fatalParseError = true; - gwi.parseErrorText = "No project column found for aggregate function"; - setError(gwi.thd, ER_INTERNAL_ERROR, gwi.parseErrorText, gwi); - return ER_CHECK_NOT_IMPLEMENTED; - } - - (*coliter)->functionParms(minSc); - } - - std::vector::iterator funciter; - - SPTP sptp(new ParseTree(minSc.get()->clone())); - - for (funciter = gwi.no_parm_func_list.begin(); funciter != gwi.no_parm_func_list.end(); ++funciter) - { - FunctionParm funcParms = (*funciter)->functionParms(); - funcParms.push_back(sptp); - (*funciter)->functionParms(funcParms); - } - - // set sequence# for subquery localCols - for (uint32_t i = 0; i < gwi.localCols.size(); i++) - gwi.localCols[i]->sequence(i); - - // append additionalRetCols to returnedCols - gwi.returnedCols.insert(gwi.returnedCols.begin(), gwi.additionalRetCols.begin(), - gwi.additionalRetCols.end()); - - csep->groupByCols(gwi.groupByCols); - csep->orderByCols(gwi.orderByCols); - csep->returnedCols(gwi.returnedCols); - csep->columnMap(gwi.columnMap); - csep->having(havingFilter); - csep->derivedTableList(gwi.derivedTbList); - csep->selectSubList(selectSubList); - csep->subSelectList(gwi.subselectList); - gwi.thd->infinidb_vtable.duplicate_field_name = false; - clearStacks(gwi); - return 0; -} - -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; - int status = getSelectPlan(gwi, select_lex, csep); - - if (status > 0) - return ER_INTERNAL_ERROR; - else if (status < 0) - return status; - - cerr << "---------------- cp_get_plan EXECUTION PLAN ----------------" << endl; - cerr << *csep << endl ; - cerr << "-------------- EXECUTION PLAN END --------------\n" << endl; - - // Derived table projection and filter optimization. - derivedTableOptimization(csep); - - return 0; -} - -int cp_get_table_plan(THD* thd, SCSEP& csep, cal_table_info& ti) -{ - gp_walk_info* gwi = ti.condInfo; - - if (!gwi) - gwi = new gp_walk_info(); - - gwi->thd = thd; - LEX* lex = thd->lex; - idbassert(lex != 0); - uint32_t sessionID = csep->sessionID(); - gwi->sessionid = sessionID; - TABLE* table = ti.msTablePtr; - boost::shared_ptr csc = CalpontSystemCatalog::makeCalpontSystemCatalog(sessionID); - csc->identity(CalpontSystemCatalog::FE); - - // get all columns that mysql needs to fetch - MY_BITMAP* read_set = table->read_set; - Field** f_ptr, *field; - gwi->columnMap.clear(); - - for (f_ptr = table->field ; (field = *f_ptr) ; f_ptr++) - { - if (bitmap_is_set(read_set, field->field_index)) - { - SimpleColumn* sc = new SimpleColumn(table->s->db.str, table->s->table_name.str, field->field_name, sessionID); - string alias(table->alias.c_ptr()); - sc->tableAlias(lower(alias)); - assert (sc); - boost::shared_ptr spsc(sc); - gwi->returnedCols.push_back(spsc); - gwi->columnMap.insert(CalpontSelectExecutionPlan::ColumnMap::value_type(string(field->field_name), spsc)); - } - } - - if (gwi->columnMap.empty()) - { - CalpontSystemCatalog::TableName tn = make_table(table->s->db.str, table->s->table_name.str); - CalpontSystemCatalog::TableAliasName tan = make_aliastable(table->s->db.str, table->s->table_name.str, table->alias.c_ptr()); - SimpleColumn* sc = getSmallestColumn(csc, tn, tan, table, *gwi); - SRCP srcp(sc); - gwi->columnMap.insert(CalpontSelectExecutionPlan::ColumnMap::value_type(sc->columnName(), srcp)); - gwi->returnedCols.push_back(srcp); - } - - // get filter - if (ti.condInfo) - { - gp_walk_info* gwi = ti.condInfo; - ParseTree* filters = 0; - ParseTree* ptp = 0; - ParseTree* rhs = 0; - - while (!gwi->ptWorkStack.empty()) - { - filters = gwi->ptWorkStack.top(); - gwi->ptWorkStack.pop(); - SimpleFilter* sf = dynamic_cast(filters->data()); - - if (sf && sf->op()->data() == "noop") - { - delete filters; - filters = 0; - - if (gwi->ptWorkStack.empty()) - break; - - continue; - } - - if (gwi->ptWorkStack.empty()) - break; - - ptp = new ParseTree(new LogicOperator("and")); - ptp->left(filters); - rhs = gwi->ptWorkStack.top(); - gwi->ptWorkStack.pop(); - ptp->right(rhs); - gwi->ptWorkStack.push(ptp); - } - - csep->filters(filters); - } - - csep->returnedCols(gwi->returnedCols); - csep->columnMap(gwi->columnMap); - CalpontSelectExecutionPlan::TableList tblist; - tblist.push_back(make_aliastable(table->s->db.str, table->s->table_name.str, table->alias.c_ptr())); - csep->tableList(tblist); - - // @bug 3321. Set max number of blocks in a dictionary file to be scanned for filtering - csep->stringScanThreshold(gwi->thd->variables.infinidb_string_scan_threshold); - - return 0; -} - -int cp_get_group_plan(THD* thd, SCSEP& csep, cal_impl_if::cal_group_info& gi) -{ - LEX* lex = thd->lex; - idbassert(lex != 0); - - SELECT_LEX select_lex = lex->select_lex; - gp_walk_info gwi; - gwi.thd = thd; - int status = getGroupPlan(gwi, select_lex, csep, gi); - - if (status > 0) - return ER_INTERNAL_ERROR; - else if (status < 0) - return status; - - return 0; -} - -/*@brief buildConstColFromFilter- change SimpleColumn into ConstColumn*/ -/*********************************************************** - * DESCRIPTION: - * Server could optimize out fields from GROUP BY list, when certain - * 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. - * PARAMETERS: - * originalSC SimpleColumn* removed field - * gwi main strucutre - * gi auxilary group_by handler structure - * RETURNS - * ConstantColumn* if originalSC equals with cond_pushed columns. - * NULL otherwise - ***********************************************************/ -ConstantColumn* buildConstColFromFilter(SimpleColumn* originalSC, -gp_walk_info& gwi, cal_group_info& gi) -{ - execplan::SimpleColumn* simpleCol; - execplan::ConstantColumn* constCol; - execplan::SOP op; - execplan::SimpleFilter* simpFilter; - execplan::ConstantColumn* result = NULL; - std::vector::iterator ptIt = gi.pushedPts.begin(); - for(; ptIt != gi.pushedPts.end(); ptIt++) - { - simpFilter = dynamic_cast((*ptIt)->data()); - if (simpFilter == NULL) - continue; - simpleCol = dynamic_cast(simpFilter->lhs()); - constCol = dynamic_cast(simpFilter->rhs()); - if(simpleCol == NULL || constCol == NULL) - continue; - op = simpFilter->op(); - if ( originalSC->sameColumn(dynamic_cast(simpleCol)) - && op.get()->op() == OP_EQ && constCol) - { -#ifdef DEBUG_WALK_COND - cerr << "buildConstColFromFilter() replaced " << endl; - cerr << simpleCol->toString() << endl; - cerr << " with " << endl; - cerr << constCol << endl; -#endif - result = constCol; - } - } - return result; -} - -int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_group_info& gi, bool isUnion) -{ -#ifdef DEBUG_WALK_COND - cerr << "getGroupPlan()" << endl; -#endif - - // rollup is currently not supported - if (select_lex.olap == ROLLUP_TYPE) - { - gwi.fatalParseError = true; - gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_ROLLUP_NOT_SUPPORT); - setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); - return ER_CHECK_NOT_IMPLEMENTED; - } - - gwi.internalDecimalScale = (gwi.thd->variables.infinidb_use_decimal_scale ? gwi.thd->variables.infinidb_decimal_scale : -1); - gwi.subSelectType = csep->subType(); - - JOIN* join = select_lex.join; - Item_cond* icp = 0; - - if ( gi.groupByWhere ) - icp = reinterpret_cast(gi.groupByWhere); - - uint32_t sessionID = csep->sessionID(); - gwi.sessionid = sessionID; - boost::shared_ptr csc = CalpontSystemCatalog::makeCalpontSystemCatalog(sessionID); - csc->identity(CalpontSystemCatalog::FE); - gwi.csc = csc; - - // @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 || gwi.thd->variables.infinidb_ordered_only) - csep->overrideLargeSideEstimate(true); - - // @bug 5741. Set a flag when in Local PM only query mode - csep->localQuery(gwi.thd->variables.infinidb_local_query); - - // @bug 3321. Set max number of blocks in a dictionary file to be scanned for filtering - csep->stringScanThreshold(gwi.thd->variables.infinidb_string_scan_threshold); - - csep->stringTableThreshold(gwi.thd->variables.infinidb_stringtable_threshold); - - csep->djsSmallSideLimit(gwi.thd->variables.infinidb_diskjoin_smallsidelimit * 1024ULL * 1024); - csep->djsLargeSideLimit(gwi.thd->variables.infinidb_diskjoin_largesidelimit * 1024ULL * 1024); - csep->djsPartitionSize(gwi.thd->variables.infinidb_diskjoin_bucketsize * 1024ULL * 1024); - - if (gwi.thd->variables.infinidb_um_mem_limit == 0) - csep->umMemLimit(numeric_limits::max()); - else - csep->umMemLimit(gwi.thd->variables.infinidb_um_mem_limit * 1024ULL * 1024); - - // populate table map and trigger syscolumn cache for all the tables (@bug 1637). - // all tables on FROM list must have at least one col in colmap - TABLE_LIST* table_ptr = gi.groupByTables; - CalpontSelectExecutionPlan::SelectList derivedTbList; - -// DEBUG -#ifdef DEBUG_WALK_COND - List_iterator sj_list_it(select_lex.sj_nests); - TABLE_LIST* sj_nest; - - while ((sj_nest = sj_list_it++)) - { - cerr << sj_nest->db << "." << sj_nest->table_name << endl; - } - -#endif - - // @bug 1796. Remember table order on the FROM list. - gwi.clauseType = FROM; - - try - { - for (; table_ptr; table_ptr = table_ptr->next_local) - { - // mysql put vtable here for from sub. we ignore it - //if (string(table_ptr->table_name).find("$vtable") != string::npos) - // continue; - - // Until we handle recursive cte: - // Checking here ensures we catch all with clauses in the query. - if (table_ptr->is_recursive_with_table()) - { - gwi.fatalParseError = true; - gwi.parseErrorText = "Recursive CTE"; - setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); - return ER_CHECK_NOT_IMPLEMENTED; - } - - string viewName = getViewName(table_ptr); - - // @todo process from subquery - if (table_ptr->derived) - { - String str; - (table_ptr->derived->first_select())->print(gwi.thd, &str, QT_INFINIDB_DERIVED); - - SELECT_LEX* select_cursor = table_ptr->derived->first_select(); - FromSubQuery fromSub(gwi, select_cursor); - string alias(table_ptr->alias); - fromSub.alias(lower(alias)); - - CalpontSystemCatalog::TableAliasName tn = make_aliasview("", "", alias, viewName); - // @bug 3852. check return execplan - SCSEP plan = fromSub.transform(); - - if (!plan) - { - setError(gwi.thd, ER_INTERNAL_ERROR, fromSub.gwip().parseErrorText, gwi); - CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); - return ER_INTERNAL_ERROR; - } - - gwi.derivedTbList.push_back(plan); - 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 - } - else if (table_ptr->view) - { - View* view = new View(table_ptr->view->select_lex, &gwi); - CalpontSystemCatalog::TableAliasName tn = make_aliastable(table_ptr->db, table_ptr->table_name, table_ptr->alias); - view->viewName(tn); - gwi.viewList.push_back(view); - view->transform(); - } - else - { - // check foreign engine tables - bool infiniDB = (table_ptr->table ? isInfiniDB(table_ptr->table) : true); - - // trigger system catalog cache - if (infiniDB) - csc->columnRIDs(make_table(table_ptr->db, table_ptr->table_name), true); - - string table_name = table_ptr->table_name; - - // @bug5523 - if (table_ptr->db && strcmp(table_ptr->db, "information_schema") == 0) - table_name = (table_ptr->schema_table_name ? table_ptr->schema_table_name : table_ptr->alias); - - CalpontSystemCatalog::TableAliasName tn = make_aliasview(table_ptr->db, table_name, table_ptr->alias, viewName, infiniDB); - gwi.tbList.push_back(tn); - CalpontSystemCatalog::TableAliasName tan = make_aliastable(table_ptr->db, table_name, table_ptr->alias, infiniDB); - gwi.tableMap[tan] = make_pair(0, table_ptr); -#ifdef DEBUG_WALK_COND - cerr << tn << endl; -#endif - } - } - - if (gwi.fatalParseError) - { - setError(gwi.thd, ER_INTERNAL_ERROR, gwi.parseErrorText, gwi); - return ER_INTERNAL_ERROR; - } - } - catch (IDBExcept& ie) - { - setError(gwi.thd, ER_INTERNAL_ERROR, ie.what(), gwi); - CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); - // @bug 3852. set error status for gwi. - gwi.fatalParseError = true; - gwi.parseErrorText = ie.what(); - return ER_INTERNAL_ERROR; - } - catch (...) - { - string emsg = IDBErrorInfo::instance()->errorMsg(ERR_LOST_CONN_EXEMGR); - // @bug3852 set error status for gwi. - gwi.fatalParseError = true; - gwi.parseErrorText = emsg; - setError(gwi.thd, ER_INTERNAL_ERROR, emsg, gwi); - CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); - return ER_INTERNAL_ERROR; - } - - csep->tableList(gwi.tbList); - - bool unionSel = false; - - gwi.clauseType = WHERE; - - - if (icp) - { - // MCOL-1052 The condition could be useless. - // 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) - { - icp->fix_fields(gwi.thd, (Item**)&icp); - } - -//#endif - gwi.fatalParseError = false; -#ifdef DEBUG_WALK_COND - cerr << "------------------ WHERE -----------------------" << endl; - icp->traverse_cond(debug_walk, &gwi, Item::POSTFIX); - cerr << "------------------------------------------------\n" << endl; -#endif - - icp->traverse_cond(gp_walk, &gwi, Item::POSTFIX); - - if (gwi.fatalParseError) - { - // if this is dervied table process phase, mysql may have not developed the plan - // completely. Do not error and eventually mysql will call JOIN::exec() again. - // related to bug 2922. Need to find a way to skip calling rnd_init for derived table - // processing. - if (gwi.thd->derived_tables_processing) - { - gwi.thd->infinidb_vtable.isUnion = false; - gwi.thd->infinidb_vtable.isUpdateWithDerive = true; - return -1; - } - - setError(gwi.thd, ER_INTERNAL_ERROR, gwi.parseErrorText, gwi); - return ER_INTERNAL_ERROR; - } - } - else if (join && join->zero_result_cause) - { - gwi.rcWorkStack.push(new ConstantColumn((int64_t)0, ConstantColumn::NUM)); - } - - uint32_t failed = buildOuterJoin(gwi, select_lex); - - if (failed) return failed; - - // @bug5764. build outer join for view, make sure outerjoin filter is appended - // to the end of the filter list. - for (uint i = 0; i < gwi.viewList.size(); i++) - { - failed = gwi.viewList[i]->processOuterJoin(gwi); - - if (failed) - break; - } - - if (failed != 0) - return failed; - - ParseTree* filters = NULL; - ParseTree* ptp = NULL; - ParseTree* lhs = NULL; - - // @bug 2932. for "select * from region where r_name" case. if icp not null and - // ptWorkStack empty, the item is in rcWorkStack. - // MySQL 5.6 (MariaDB?). when icp is null and zero_result_cause is set, a constant 0 - // is pushed to rcWorkStack. - if (/*icp && */gwi.ptWorkStack.empty() && !gwi.rcWorkStack.empty()) - { - filters = new ParseTree(gwi.rcWorkStack.top()); - gwi.rcWorkStack.pop(); - } - - while (!gwi.ptWorkStack.empty()) - { - filters = gwi.ptWorkStack.top(); - gwi.ptWorkStack.pop(); - - if (gwi.ptWorkStack.empty()) - break; - - ptp = new ParseTree(new LogicOperator("and")); - //ptp->left(filters); - ptp->right(filters); - lhs = gwi.ptWorkStack.top(); - gwi.ptWorkStack.pop(); - //ptp->right(rhs); - ptp->left(lhs); - gwi.ptWorkStack.push(ptp); - } - - if (filters) - { - csep->filters(filters); -#ifdef DEBUG_WALK_COND - filters->drawTree("/tmp/filter1.dot"); -#endif - } - - gwi.clauseType = SELECT; -#ifdef DEBUG_WALK_COND - { - cerr << "------------------- SELECT --------------------" << endl; - List_iterator_fast it(*gi.groupByFields); - Item* item; - - while ((item = it++)) - { - debug_walk(item, 0); - } - - cerr << "-----------------------------------------------\n" << endl; - } -#endif - - // populate returnedcolumnlist and columnmap - 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. - clearStacks(gwi); - - // indicate the starting pos of scalar returned column, because some join column - // has been inserted to the returned column list. - if (gwi.subQuery) - { - ScalarSub* scalar = dynamic_cast(gwi.subQuery); - - if (scalar) - scalar->returnedColPos(gwi.additionalRetCols.size()); - } - - CalpontSelectExecutionPlan::SelectList selectSubList; - - while ((item = it++)) - { - string itemAlias = (item->name ? item->name : ""); - - // @bug 5916. Need to keep checking until getting concret item in case - // of nested view. - while (item->type() == Item::REF_ITEM) - { - Item_ref* ref = (Item_ref*)item; - item = (*(ref->ref)); - } - - Item::Type itype = item->type(); - - switch (itype) - { - case Item::FIELD_ITEM: - { - Item_field* ifp = (Item_field*)item; - SimpleColumn* sc = NULL; - ConstantColumn* constCol = NULL; - - if (ifp->field_name && string(ifp->field_name) == "*") - { - collectAllCols(gwi, ifp); - break; - } - - sc = buildSimpleColumn(ifp, gwi); - - if (sc) - { - constCol = buildConstColFromFilter(sc, gwi, gi); - 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); - 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 - { - if (!itemAlias.empty()) - sc->alias(itemAlias); - - sel_cols_in_create += fullname + " `" + escapeBackTick(sc->alias().c_str()) + "`"; - } - - if (ifp->is_autogenerated_name) - gwi.selectCols.push_back("`" + escapeBackTick(fullname.c_str()) + "`" + " `" + - escapeBackTick(itemAlias.empty() ? ifp->name : itemAlias.c_str()) + "`"); - else - gwi.selectCols.push_back("`" + escapeBackTick((itemAlias.empty() ? ifp->name : itemAlias.c_str())) + "`"); - - // MCOL-1052 Replace SimpleColumn with ConstantColumn, - // since it must have a single value only. - if(constCol) - { - gwi.returnedCols.push_back(spcc); - gwi.columnMap.insert(CalpontSelectExecutionPlan::ColumnMap::value_type(string(ifp->field_name), spcc)); - } - else - { - gwi.returnedCols.push_back(spsc); - gwi.columnMap.insert(CalpontSelectExecutionPlan::ColumnMap::value_type(string(ifp->field_name), spsc)); - } - TABLE_LIST* tmp = 0; - - if (ifp->cached_table) - tmp = ifp->cached_table; - - gwi.tableMap[make_aliastable(sc->schemaName(), sc->tableName(), sc->tableAlias(), sc->isInfiniDB())] = - make_pair(1, tmp); - } - else - { - setError(gwi.thd, ER_INTERNAL_ERROR, gwi.parseErrorText, gwi); - delete sc; - return ER_INTERNAL_ERROR; - } - - break; - } - - //aggregate column - case Item::SUM_FUNC_ITEM: - { - ReturnedColumn* ac = buildAggregateColumn(item, gwi); - - if (gwi.fatalParseError) - { - // e.g., non-support ref column - setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); - delete ac; - return ER_CHECK_NOT_IMPLEMENTED; - } - - // add this agg col to returnedColumnList - boost::shared_ptr spac(ac); - gwi.returnedCols.push_back(spac); - // This item will be used in HAVING later. - Item_func_or_sum* isfp = reinterpret_cast(item); - if ( ! isfp->name_length ) - { - gwi.havingAggColsItems.push_back(item); - } - - gwi.selectCols.push_back('`' + escapeBackTick(spac->alias().c_str()) + '`'); - String str(256); - item->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()) + " `" + escapeBackTick(spac->alias().c_str()) + "`"; - break; - } - - case Item::FUNC_ITEM: - { - Item_func* ifp = reinterpret_cast(item); - - // @bug4383. error out non-support stored function - if (ifp->functype() == Item_func::FUNC_SP) - { - gwi.fatalParseError = true; - gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_SP_FUNCTION_NOT_SUPPORT); - setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); - return ER_CHECK_NOT_IMPLEMENTED; - } - - if (string(ifp->func_name()) == "xor") - { - gwi.fatalParseError = true; - gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_FILTER_COND_EXP); - setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); - return ER_CHECK_NOT_IMPLEMENTED; - } - - uint16_t parseInfo = 0; - vector tmpVec; - bool hasNonSupportItem = false; - parse_item(ifp, tmpVec, hasNonSupportItem, parseInfo); - - if (ifp->has_subquery() || - string(ifp->func_name()) == string("") || - ifp->functype() == Item_func::NOT_ALL_FUNC || - parseInfo & SUB_BIT) - { - gwi.fatalParseError = true; - gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_SELECT_SUB); - setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); - return ER_CHECK_NOT_IMPLEMENTED; - } - - ReturnedColumn* rc = buildFunctionColumn(ifp, gwi, hasNonSupportItem); - SRCP srcp(rc); - - if (rc) - { - 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); - - if (ifp->name) - srcp->alias(ifp->name); - - 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) + "`"); + ord_item->print(&str, QT_INFINIDB_NO_QUOTE); + ord_cols += string(str.c_ptr()); } - break; - } - - //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 + "`"; - gwi.selectCols.push_back("`" + escapeBackTick(ifp->name) + "`"); + if (ordercol->direction != ORDER::ORDER_ASC) + ord_cols += " desc"; } } - else // InfiniDB Non support functions still go through post process for now + + if (ord_cols.length() > 0) // has order by { - hasNonSupportItem = false; - uint32_t before_size = funcFieldVec.size(); - parse_item(ifp, funcFieldVec, hasNonSupportItem, parseInfo); - uint32_t after_size = funcFieldVec.size(); - - // group by func and func in subquery can not be post processed - // @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) && - !hasNonSupportItem && (after_size - before_size) == 0 && - !(parseInfo & AGG_BIT) && !(parseInfo & SUB_BIT) && - string(ifp->func_name()) != "set_user_var") - { - String val, *str = ifp->val_str(&val); - string valStr; - - if (str) - valStr.assign(str->ptr(), str->length()); - - ConstantColumn* cc = NULL; - - if (!str) - { - cc = new ConstantColumn("", ConstantColumn::NULLDATA); - } - else if (ifp->result_type() == STRING_RESULT) - { - cc = new ConstantColumn(valStr, ConstantColumn::LITERAL); - } - else if (ifp->result_type() == DECIMAL_RESULT) - { - cc = buildDecimalColumn(ifp, gwi); - } - else - { - cc = new ConstantColumn(valStr, ConstantColumn::NUM); - cc->resultType(colType_MysqlToIDB(item)); - } - - SRCP srcp(cc); - - if (ifp->name) - cc->alias(ifp->name); - - gwi.returnedCols.push_back(srcp); - - // clear the error set by buildFunctionColumn - gwi.fatalParseError = false; - gwi.parseErrorText = ""; - break; - } - else if (hasNonSupportItem || parseInfo & AGG_BIT || parseInfo & SUB_BIT || - (gwi.fatalParseError && gwi.subQuery)) - { - if (gwi.parseErrorText.empty()) - { - 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; - } - else if ( gwi.subQuery && (isPredicateFunction(ifp, &gwi) || ifp->type() == Item::COND_ITEM )) - { - gwi.fatalParseError = true; - gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_FILTER_COND_EXP); - setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); - return ER_CHECK_NOT_IMPLEMENTED; - } - - //@Bug 3030 Add error check for dml statement - if ( ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE ) || ((gwi.thd->lex)->sql_command == SQLCOM_DELETE ) || ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE_MULTI ) || ((gwi.thd->lex)->sql_command == SQLCOM_DELETE_MULTI ) ) - { - if ( after_size - before_size != 0 ) - { - gwi.parseErrorText = ifp->func_name(); - 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); - gwi.selectCols.push_back(string(funcStr.c_ptr()) + " `" + escapeBackTick(ifp->name) + "`"); - // clear the error set by buildFunctionColumn - gwi.fatalParseError = false; - gwi.parseErrorText = ""; - } + gwi.thd->infinidb_vtable.has_order_by = true; + csep->hasOrderBy(true); + ord_cols = " order by " + ord_cols; + select_query += ord_cols; } - - break; } + } // ORDER BY processing ends here - case Item::INT_ITEM: + if ( gi.groupByDistinct ) + csep->distinct(true); + + // add the smallest column to count(*) parm. + // select constant in subquery case + std::vector::iterator coliter; + + if (!minSc) + { + if (!gwi.returnedCols.empty()) + minSc = gwi.returnedCols[0]; + else if (!gwi.additionalRetCols.empty()) + minSc = gwi.additionalRetCols[0]; + } + + // @bug3523, count(*) on subquery always pick column[0]. + SimpleColumn* sc = dynamic_cast(minSc.get()); + + if (sc && sc->schemaName().empty()) + { + if (gwi.derivedTbList.size() >= 1) { - 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 && string(item->name) == "Not_used") - continue; - - // @bug3509. Constant column is sent to ExeMgr now. - SRCP srcp(buildReturnedColumn(item, gwi, gwi.fatalParseError)); - - if (item->name) - srcp->alias(item->name); - - gwi.returnedCols.push_back(srcp); - - 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 += ", "; - - sel_cols_in_create += oss.str(); - gwi.selectCols.push_back(oss.str()); - } - - break; + SimpleColumn* sc1 = new SimpleColumn(); + sc1->columnName(sc->columnName()); + sc1->tableName(sc->tableName()); + sc1->tableAlias(sc->tableAlias()); + sc1->viewName(lower(sc->viewName())); + sc1->colPosition(0); + minSc.reset(sc1); } + } - 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) - srcp->alias(item->name); - - 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) - srcp->alias(item->name); - - 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; - } - - case Item::NULL_ITEM: - { - /*if ( ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE ) || ((gwi.thd->lex)->sql_command == SQLCOM_DELETE ) || ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE_MULTI ) || ((gwi.thd->lex)->sql_command == SQLCOM_DELETE_MULTI ) ) - { } - else - { - SRCP srcp(buildReturnedColumn(item, gwi, gwi.fatalParseError)); - gwi.returnedCols.push_back(srcp); - - if (item->name) - srcp->alias(item->name); - - 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"); - }*/ - - break; - } - - case Item::SUBSELECT_ITEM: - { - Item_subselect* sub = (Item_subselect*)item; - - if (sub->substype() != Item_subselect::SINGLEROW_SUBS) - { - gwi.fatalParseError = true; - gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_SELECT_SUB); - setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); - return ER_CHECK_NOT_IMPLEMENTED; - } - -#ifdef DEBUG_WALK_COND - cerr << "SELECT clause SUBSELECT Item: " << sub->substype() << endl; - JOIN* join = sub->get_select_lex()->join; - - if (join) - { - Item_cond* cond = reinterpret_cast(join->conds); - - if (cond) - cond->traverse_cond(debug_walk, &gwi, Item::POSTFIX); - } - - cerr << "Finish SELECT clause subselect item traversing" << endl; -#endif - SelectSubQuery* selectSub = new SelectSubQuery(gwi, sub); - //selectSub->gwip(&gwi); - SCSEP ssub = selectSub->transform(); - - if (!ssub || gwi.fatalParseError) - { - if (gwi.parseErrorText.empty()) - gwi.parseErrorText = "Unsupported Item in SELECT subquery."; - - setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); - return ER_CHECK_NOT_IMPLEMENTED; - } - - selectSubList.push_back(ssub); - SimpleColumn* rc = new SimpleColumn(); - rc->colSource(rc->colSource() | SELECT_SUB); - - if (sub->get_select_lex()->get_table_list()) - rc->viewName(lower(getViewName(sub->get_select_lex()->get_table_list()))); - - if (sub->name) - rc->alias(sub->name); - - 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) - { - sel_cols_in_create += "`" + escapeBackTick(sub->name) + "`"; - gwi.selectCols.push_back(sub->name); - } - else - { - sel_cols_in_create += "`" + escapeBackTick(str.c_ptr()) + "`"; - gwi.selectCols.push_back("`" + escapeBackTick(str.c_ptr()) + "`"); - } - - break; - } - - case Item::COND_ITEM: + for (coliter = gwi.count_asterisk_list.begin(); coliter != gwi.count_asterisk_list.end(); ++coliter) + { + // @bug5977 @note should never throw this, but checking just in case. + // When ExeMgr fix is ready, this should not error out... + if (dynamic_cast(minSc.get())) { gwi.fatalParseError = true; - gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_FILTER_COND_EXP); - setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); + gwi.parseErrorText = "No project column found for aggregate function"; + setError(gwi.thd, ER_INTERNAL_ERROR, gwi.parseErrorText, gwi); return ER_CHECK_NOT_IMPLEMENTED; } - case Item::EXPR_CACHE_ITEM: - { - printf("EXPR_CACHE_ITEM in getSelectPlan\n"); - gwi.fatalParseError = true; - gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_UNKNOWN_COL); - setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); - return ER_CHECK_NOT_IMPLEMENTED; - } - - case Item::WINDOW_FUNC_ITEM: - { - SRCP srcp(buildWindowFunctionColumn(item, gwi, gwi.fatalParseError)); - - if (!srcp || gwi.fatalParseError) - { - if (gwi.parseErrorText.empty()) - gwi.parseErrorText = "Unsupported Item in SELECT subquery."; - - setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); - return ER_CHECK_NOT_IMPLEMENTED; - } - - gwi.returnedCols.push_back(srcp); - break; - } - - default: - { - break; - } + (*coliter)->functionParms(minSc); } + + std::vector::iterator funciter; + + SPTP sptp(new ParseTree(minSc.get()->clone())); + + for (funciter = gwi.no_parm_func_list.begin(); funciter != gwi.no_parm_func_list.end(); ++funciter) + { + FunctionParm funcParms = (*funciter)->functionParms(); + funcParms.push_back(sptp); + (*funciter)->functionParms(funcParms); + } + + // set sequence# for subquery localCols + for (uint32_t i = 0; i < gwi.localCols.size(); i++) + gwi.localCols[i]->sequence(i); + + // append additionalRetCols to returnedCols + gwi.returnedCols.insert(gwi.returnedCols.begin(), gwi.additionalRetCols.begin(), + gwi.additionalRetCols.end()); + + csep->groupByCols(gwi.groupByCols); + csep->orderByCols(gwi.orderByCols); + csep->returnedCols(gwi.returnedCols); + csep->columnMap(gwi.columnMap); + csep->having(havingFilter); + csep->derivedTableList(gwi.derivedTbList); + csep->selectSubList(selectSubList); + csep->subSelectList(gwi.subselectList); + gwi.thd->infinidb_vtable.duplicate_field_name = false; + clearStacks(gwi); + return 0; } - // @bug4388 normalize the project coltypes for union main select list - if (!csep->unionVec().empty()) - { - for (uint32_t i = 0; i < gwi.returnedCols.size(); i++) - { - vector coltypes; - - for (uint32_t j = 0; j < csep->unionVec().size(); j++) - { - coltypes.push_back( - dynamic_cast(csep->unionVec()[j].get())->returnedCols()[i]->resultType()); - - // @bug5976. set hasAggregate true for the main column if - // one corresponding union column has aggregate - if (dynamic_cast(csep->unionVec()[j].get())->returnedCols()[i]->hasAggregate()) - gwi.returnedCols[i]->hasAggregate(true); - } - - gwi.returnedCols[i]->resultType(dataconvert::DataConvert::convertUnionColType(coltypes)); - } - } - - // Having clause handling - gwi.clauseType = HAVING; - clearStacks(gwi); - ParseTree* havingFilter = 0; - // clear fatalParseError that may be left from post process functions - gwi.fatalParseError = false; - gwi.parseErrorText = ""; - - if (gi.groupByHaving != 0) - { - Item_cond* having = reinterpret_cast(gi.groupByHaving); -#ifdef DEBUG_WALK_COND - cerr << "------------------- HAVING ---------------------" << endl; - having->traverse_cond(debug_walk, &gwi, Item::POSTFIX); - cerr << "------------------------------------------------\n" << endl; -#endif - having->traverse_cond(gp_walk, &gwi, Item::POSTFIX); - - if (gwi.fatalParseError) - { - setError(gwi.thd, ER_INTERNAL_ERROR, gwi.parseErrorText, gwi); - return ER_INTERNAL_ERROR; - } - - ParseTree* ptp = 0; - ParseTree* rhs = 0; - - // @bug 4215. some function filter will be in the rcWorkStack. - if (gwi.ptWorkStack.empty() && !gwi.rcWorkStack.empty()) - { - havingFilter = new ParseTree(gwi.rcWorkStack.top()); - gwi.rcWorkStack.pop(); - } - - while (!gwi.ptWorkStack.empty()) - { - havingFilter = gwi.ptWorkStack.top(); - gwi.ptWorkStack.pop(); - - if (gwi.ptWorkStack.empty()) - break; - - ptp = new ParseTree(new LogicOperator("and")); - ptp->left(havingFilter); - rhs = gwi.ptWorkStack.top(); - gwi.ptWorkStack.pop(); - ptp->right(rhs); - gwi.ptWorkStack.push(ptp); - } - } - - // for post process expressions on the select list - // error out post process for union and sub select unit - if (isUnion || gwi.subSelectType != CalpontSelectExecutionPlan::MAIN_SELECT) - { - if (funcFieldVec.size() != 0 && !gwi.fatalParseError) - { - string emsg("Fatal parse error in vtable mode: Unsupported Items in union or sub select unit"); - setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, emsg); - return ER_CHECK_NOT_IMPLEMENTED; - } - } - - for (uint32_t i = 0; i < funcFieldVec.size(); i++) - { - SimpleColumn* sc = buildSimpleColumn(funcFieldVec[i], gwi); - - if (!sc || gwi.fatalParseError) - { - string emsg; - - if (gwi.parseErrorText.empty()) - { - emsg = "un-recognized column"; - - if (funcFieldVec[i]->name) - emsg += string(funcFieldVec[i]->name); - } - else - { - emsg = gwi.parseErrorText; - } - - setError(gwi.thd, ER_INTERNAL_ERROR, emsg, gwi); - return ER_INTERNAL_ERROR; - } - - String str; - funcFieldVec[i]->print(&str, QT_INFINIDB_NO_QUOTE); - sc->alias(string(str.c_ptr())); - //sc->tableAlias(funcFieldVec[i]->table_name); - sc->tableAlias(sc->tableAlias()); - SRCP srcp(sc); - uint32_t j = 0; - - for (; j < gwi.returnedCols.size(); j++) - { - if (sc->sameColumn(gwi.returnedCols[j].get())) - { - SimpleColumn* field = dynamic_cast(gwi.returnedCols[j].get()); - - if (field && field->alias() == sc->alias()) - break; - } - } - - if (j == gwi.returnedCols.size()) - { - gwi.returnedCols.push_back(srcp); - gwi.columnMap.insert(CalpontSelectExecutionPlan::ColumnMap::value_type(string(funcFieldVec[i]->field_name), 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) - { - gwi.clauseType = GROUP_BY; - Item* nonSupportItem = NULL; - ORDER* groupcol = reinterpret_cast(gi.groupByGroup); - - // check if window functions are in order by. InfiniDB process order by list if - // window functions are involved, either in order by or projection. - bool hasWindowFunc = gwi.hasWindowFunc; - gwi.hasWindowFunc = false; - - for (; groupcol; groupcol = groupcol->next) - { - if ((*(groupcol->item))->type() == Item::WINDOW_FUNC_ITEM) - gwi.hasWindowFunc = true; - } - - if (gwi.hasWindowFunc) - { - gwi.fatalParseError = true; - gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_WF_NOT_ALLOWED, "GROUP BY clause"); - setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); - return ER_CHECK_NOT_IMPLEMENTED; - } - - gwi.hasWindowFunc = hasWindowFunc; - groupcol = reinterpret_cast(gi.groupByGroup); - - for (; groupcol; groupcol = groupcol->next) - { - Item* groupItem = *(groupcol->item); - - // @bug5993. Could be nested ref. - while (groupItem->type() == Item::REF_ITEM) - groupItem = (*((Item_ref*)groupItem)->ref); - - if (groupItem->type() == Item::FUNC_ITEM) - { - Item_func* ifp = (Item_func*)groupItem; - - // call buildFunctionColumn here mostly for finding out - // non-support column on GB list. Should be simplified. - ReturnedColumn* fc = buildFunctionColumn(ifp, gwi, gwi.fatalParseError); - - if (!fc || gwi.fatalParseError) - { - nonSupportItem = ifp; - break; - } - - if (groupcol->in_field_list && groupcol->counter_used) - { - delete fc; - fc = gwi.returnedCols[groupcol->counter - 1].get(); - SRCP srcp(fc->clone()); - - // check if no column parm - for (uint32_t i = 0; i < gwi.no_parm_func_list.size(); i++) - { - if (gwi.no_parm_func_list[i]->expressionId() == fc->expressionId()) - { - gwi.no_parm_func_list.push_back(dynamic_cast(srcp.get())); - break; - } - } - - srcp->orderPos(groupcol->counter - 1); - gwi.groupByCols.push_back(srcp); - continue; - } - else if (!groupItem->is_autogenerated_name) // alias - { - uint32_t i = 0; - - for (; i < gwi.returnedCols.size(); i++) - { - if (string(groupItem->name) == gwi.returnedCols[i]->alias()) - { - ReturnedColumn* rc = gwi.returnedCols[i]->clone(); - rc->orderPos(i); - gwi.groupByCols.push_back(SRCP(rc)); - delete fc; - break; - } - } - - if (i == gwi.returnedCols.size()) - { - nonSupportItem = groupItem; - break; - } - } - else - { - uint32_t i = 0; - - for (; i < gwi.returnedCols.size(); i++) - { - if (fc->operator==(gwi.returnedCols[i].get())) - { - ReturnedColumn* rc = gwi.returnedCols[i]->clone(); - rc->orderPos(i); - gwi.groupByCols.push_back(SRCP(rc)); - delete fc; - break; - } - } - - if (i == gwi.returnedCols.size()) - { - gwi.groupByCols.push_back(SRCP(fc)); - break; - } - } - } - else if (groupItem->type() == Item::FIELD_ITEM) - { - Item_field* ifp = (Item_field*)groupItem; - // this GB col could be an alias of F&E on the SELECT clause, not necessarily a field. - ReturnedColumn* rc = buildSimpleColumn(ifp, gwi); - SimpleColumn* sc = dynamic_cast(rc); - - for (uint32_t j = 0; j < gwi.returnedCols.size(); j++) - { - if (sc) - { - if (sc->sameColumn(gwi.returnedCols[j].get())) - { - sc->orderPos(j); - break; - } - else if (strcasecmp(sc->alias().c_str(), gwi.returnedCols[j]->alias().c_str()) == 0) - { - rc = gwi.returnedCols[j].get()->clone(); - rc->orderPos(j); - break; - } - } - else - { - if (ifp->name && string(ifp->name) == gwi.returnedCols[j].get()->alias()) - { - rc = gwi.returnedCols[j].get()->clone(); - rc->orderPos(j); - break; - } - } - } - - if (!rc) - { - nonSupportItem = ifp; - break; - } - - SRCP srcp(rc); - - // bug 3151 - AggregateColumn* ac = dynamic_cast(rc); - - if (ac) - { - nonSupportItem = ifp; - break; - } - - gwi.groupByCols.push_back(srcp); - gwi.columnMap.insert(CalpontSelectExecutionPlan::ColumnMap::value_type(string(ifp->field_name), srcp)); - } - // @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)) - { - ReturnedColumn* rc = 0; - - for (uint32_t j = 0; j < gwi.returnedCols.size(); j++) - { - if (groupItem->name && string(groupItem->name) == gwi.returnedCols[j].get()->alias()) - { - rc = gwi.returnedCols[j].get()->clone(); - rc->orderPos(j); - break; - } - } - - if (!rc) - { - nonSupportItem = groupItem; - break; - } - - gwi.groupByCols.push_back(SRCP(rc)); - } - else if ((*(groupcol->item))->type() == Item::SUBSELECT_ITEM) - { - if (!groupcol->in_field_list || !groupItem->name) - { - nonSupportItem = groupItem; - } - else - { - uint32_t i = 0; - - for (; i < gwi.returnedCols.size(); i++) - { - if (string(groupItem->name) == gwi.returnedCols[i]->alias()) - { - ReturnedColumn* rc = gwi.returnedCols[i]->clone(); - rc->orderPos(i); - gwi.groupByCols.push_back(SRCP(rc)); - break; - } - } - - if (i == gwi.returnedCols.size()) - { - nonSupportItem = groupItem; - } - } - } - // @bug 3761. - else if (groupcol->counter_used) - { - if (gwi.returnedCols.size() <= (uint32_t)(groupcol->counter - 1)) - { - nonSupportItem = groupItem; - } - else - { - gwi.groupByCols.push_back(SRCP(gwi.returnedCols[groupcol->counter - 1]->clone())); - } - } - else - { - nonSupportItem = groupItem; - } - - } - - // @bug 4756. Add internal groupby column for correlated join to the groupby list - if (gwi.aggOnSelect && !gwi.subGroupByCols.empty()) - gwi.groupByCols.insert(gwi.groupByCols.end(), gwi.subGroupByCols.begin(), gwi.subGroupByCols.end()); - - // this is window func on SELECT becuase ORDER BY has not been processed - if (!gwi.windowFuncList.empty() && !gwi.subGroupByCols.empty()) - { - for (uint32_t i = 0; i < gwi.windowFuncList.size(); i++) - { - if (gwi.windowFuncList[i]->hasWindowFunc()) - { - vector windowFunctions = gwi.windowFuncList[i]->windowfunctionColumnList(); - - for (uint32_t j = 0; j < windowFunctions.size(); j++) - windowFunctions[j]->addToPartition(gwi.subGroupByCols); - } - } - } - - if (nonSupportItem) - { - Message::Args args; - - if (nonSupportItem->name) - args.add("'" + string(nonSupportItem->name) + "'"); - else - args.add(""); - - gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_GROUP_BY, args); - setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); - return ER_CHECK_NOT_IMPLEMENTED; - } - } // GROUP processing ends here - - - if (gwi.thd->infinidb_vtable.vtable_state == THD::INFINIDB_CREATE_VTABLE) - { - 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()); - algorithm::to_lower(lower_create_query); - 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. - for (; ordercol; ordercol = ordercol->next) - { - if ((*(ordercol->item))->type() == Item::WINDOW_FUNC_ITEM) - gwi.hasWindowFunc = true; - } - - // re-visit the first of ordercol list - ordercol = reinterpret_cast(gi.groupByOrder); - - // 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) - - for (; ordercol; ordercol = ordercol->next) - { - ReturnedColumn* rc = NULL; - - if (ordercol->in_field_list && ordercol->counter_used) - { - rc = gwi.returnedCols[ordercol->counter - 1]->clone(); - rc->orderPos(ordercol->counter - 1); - // can not be optimized off if used in order by with counter. - // set with self derived table alias if it's derived table - gwi.returnedCols[ordercol->counter - 1]->incRefCount(); - } - else - { - 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(); - else if (ord_item->type() == Item::SUBSELECT_ITEM) - gwi.fatalParseError = true; - else - rc = buildReturnedColumn(ord_item, gwi, gwi.fatalParseError); - - // Looking for a match for this item in GROUP BY list. - if ( rc && ord_item->type() == Item::FIELD_ITEM ) - { - execplan::CalpontSelectExecutionPlan::ReturnedColumnList::iterator iter = gwi.groupByCols.begin(); - for( ; iter != gwi.groupByCols.end(); iter++ ) - { - if( rc->sameColumn((*iter).get()) ) - break; - } - - // MCOL-1052 Find and remove the optimized field - // from ORDER using cond_pushed filters. - if(buildConstColFromFilter( - dynamic_cast(rc),gwi, gi)) - { - break; - } - // MCOL-1052 GROUP BY items list doesn't contain - // 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) - ostream << iip->field_name; - else - ostream << "unknown field"; - ostream << "'"; - 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; - } - } - - // @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. - if (!rc || gwi.fatalParseError) - { - gwi.fatalParseError = false; - Item* item_ptr = ordercol->item_ptr; - - while (item_ptr->type() == Item::REF_ITEM) - item_ptr = *(((Item_ref*)item_ptr)->ref); - - rc = buildReturnedColumn(item_ptr, gwi, gwi.fatalParseError); - } - - // This ORDER BY item must be an agg function - - // the ordercol->item_ptr and exteded SELECT list - // must contain the corresponding item. - if (!rc) - { - Item* item_ptr = ordercol->item_ptr; - if (item_ptr) - rc = buildReturnedColumn(item_ptr, gwi, gwi.fatalParseError); - } - - if (!rc) - { - string emsg = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_ORDER_BY); - gwi.parseErrorText = emsg; - setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, emsg, gwi); - return ER_CHECK_NOT_IMPLEMENTED; - } - } - - if (ordercol->direction == ORDER::ORDER_ASC) - rc->asc(true); - else - rc->asc(false); - - gwi.orderByCols.push_back(SRCP(rc)); - } - - - // make sure columnmap, returnedcols and count(*) arg_list are not empty - TableMap::iterator tb_iter = gwi.tableMap.begin(); - - try - { - for (; tb_iter != gwi.tableMap.end(); tb_iter++) - { - if ((*tb_iter).second.first == 1) continue; - - CalpontSystemCatalog::TableAliasName tan = (*tb_iter).first; - CalpontSystemCatalog::TableName tn = make_table((*tb_iter).first.schema, (*tb_iter).first.table); - SimpleColumn* sc = getSmallestColumn(csc, tn, tan, (*tb_iter).second.second->table, gwi); - SRCP srcp(sc); - gwi.columnMap.insert(CalpontSelectExecutionPlan::ColumnMap::value_type(sc->columnName(), srcp)); - (*tb_iter).second.first = 1; - } - } - catch (runtime_error& e) - { - setError(gwi.thd, ER_INTERNAL_ERROR, e.what(), gwi); - CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); - return ER_INTERNAL_ERROR; - } - catch (...) - { - string emsg = IDBErrorInfo::instance()->errorMsg(ERR_LOST_CONN_EXEMGR); - setError(gwi.thd, ER_INTERNAL_ERROR, emsg, gwi); - CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); - return ER_INTERNAL_ERROR; - } - - if (!gwi.count_asterisk_list.empty() || !gwi.no_parm_func_list.empty() || - gwi.returnedCols.empty()) - { - // get the smallest column from colmap - CalpontSelectExecutionPlan::ColumnMap::const_iterator iter; - int minColWidth = 0; - CalpontSystemCatalog::ColType ct; - - try - { - for (iter = gwi.columnMap.begin(); iter != gwi.columnMap.end(); ++iter) - { - // should always not null - SimpleColumn* sc = dynamic_cast(iter->second.get()); - - if (sc && !(sc->joinInfo() & JOIN_CORRELATED)) - { - ct = csc->colType(sc->oid()); - - if (minColWidth == 0) - { - minColWidth = ct.colWidth; - minSc = iter->second; - } - else if (ct.colWidth < minColWidth) - { - minColWidth = ct.colWidth; - minSc = iter->second; - } - } - } - } - catch (...) - { - string emsg = IDBErrorInfo::instance()->errorMsg(ERR_LOST_CONN_EXEMGR); - setError(gwi.thd, ER_INTERNAL_ERROR, emsg, gwi); - CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); - return ER_INTERNAL_ERROR; - } - - if (gwi.returnedCols.empty() && gwi.additionalRetCols.empty()) - gwi.returnedCols.push_back(minSc); - } - - 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 = 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 - - for (; table_ptr; table_ptr = table_ptr->next_local) - { - if (string(table_ptr->table_name).find("$vtable") != string::npos) - continue; - - if (table_ptr->derived) - { - if (aliasSet.find(table_ptr->alias) != 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); - firstTb = false; - aliasSet.insert(table_ptr->alias); - } - else if (table_ptr->view) - { - if (aliasSet.find(table_ptr->alias) != aliasSet.end()) - continue; - - if (!firstTb) - create_query += ", "; - - create_query += string(table_ptr->db) + "." + string(table_ptr->table_name) + - string(" `") + escapeBackTick(table_ptr->alias) + string("`"); - aliasSet.insert(table_ptr->alias); - 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) + "_" + - string(table_ptr->alias)) != aliasSet.end()) - continue; - - if (!firstTb) - create_query += ", "; - - create_query += string(table_ptr->db) + "." + string(table_ptr->table_name) + string(" "); - create_query += string(" `") + - escapeBackTick(table_ptr->referencing_view->alias) + "_" + - escapeBackTick(table_ptr->alias) + string("`"); - aliasSet.insert(string(table_ptr->referencing_view->alias) + "_" + - string(table_ptr->alias)); - } - else - { - if (aliasSet.find(table_ptr->alias) != aliasSet.end()) - continue; - - if (!firstTb) - create_query += ", "; - - create_query += string(table_ptr->db) + "." + string(table_ptr->table_name) + string(" "); - create_query += string("`") + escapeBackTick(table_ptr->alias) + string("`"); - aliasSet.insert(table_ptr->alias); - } - - 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) - { - // 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 && 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) - fullname += string(field->field_name); - - 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, 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) + '`'; - } - - else if (ord_item->name) - { - // for union order by 1 case. For unknown reason, it doesn't show in_field_list - if (ord_item->type() == Item::INT_ITEM) - { - ord_cols += ord_item->name; - } - else if (ord_item->type() == Item::SUBSELECT_ITEM) - { - string emsg = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_ORDER_BY); - setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, emsg, gwi); - return ER_CHECK_NOT_IMPLEMENTED; - } - else - { - ord_cols += string(" `") + escapeBackTick(ord_item->name) + '`'; - } - } - else if (ord_item->type() == Item::FUNC_ITEM) - { - // @bug5636. check if this order by column is on the select list - ReturnedColumn* rc = buildFunctionColumn((Item_func*)(ord_item), gwi, gwi.fatalParseError); - - 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(); - break; - } - } - } - else - { - String str; - ord_item->print(&str, QT_INFINIDB_NO_QUOTE); - ord_cols += string(str.c_ptr()); - } - - if (ordercol->direction != ORDER::ORDER_ASC) - ord_cols += " desc"; - } - } - - if (ord_cols.length() > 0) // has order by - { - gwi.thd->infinidb_vtable.has_order_by = true; - csep->hasOrderBy(true); - ord_cols = " order by " + ord_cols; - select_query += ord_cols; - } - } - } // ORDER BY processing ends here - - if ( gi.groupByDistinct ) - csep->distinct(true); - - // add the smallest column to count(*) parm. - // select constant in subquery case - std::vector::iterator coliter; - - if (!minSc) - { - if (!gwi.returnedCols.empty()) - minSc = gwi.returnedCols[0]; - else if (!gwi.additionalRetCols.empty()) - minSc = gwi.additionalRetCols[0]; - } - - // @bug3523, count(*) on subquery always pick column[0]. - SimpleColumn* sc = dynamic_cast(minSc.get()); - - if (sc && sc->schemaName().empty()) - { - if (gwi.derivedTbList.size() >= 1) - { - SimpleColumn* sc1 = new SimpleColumn(); - sc1->columnName(sc->columnName()); - sc1->tableName(sc->tableName()); - sc1->tableAlias(sc->tableAlias()); - sc1->viewName(lower(sc->viewName())); - sc1->colPosition(0); - minSc.reset(sc1); - } - } - - for (coliter = gwi.count_asterisk_list.begin(); coliter != gwi.count_asterisk_list.end(); ++coliter) - { - // @bug5977 @note should never throw this, but checking just in case. - // When ExeMgr fix is ready, this should not error out... - if (dynamic_cast(minSc.get())) - { - gwi.fatalParseError = true; - gwi.parseErrorText = "No project column found for aggregate function"; - setError(gwi.thd, ER_INTERNAL_ERROR, gwi.parseErrorText, gwi); - return ER_CHECK_NOT_IMPLEMENTED; - } - - (*coliter)->functionParms(minSc); - } - - std::vector::iterator funciter; - - SPTP sptp(new ParseTree(minSc.get()->clone())); - - for (funciter = gwi.no_parm_func_list.begin(); funciter != gwi.no_parm_func_list.end(); ++funciter) - { - FunctionParm funcParms = (*funciter)->functionParms(); - funcParms.push_back(sptp); - (*funciter)->functionParms(funcParms); - } - - // set sequence# for subquery localCols - for (uint32_t i = 0; i < gwi.localCols.size(); i++) - gwi.localCols[i]->sequence(i); - - // append additionalRetCols to returnedCols - gwi.returnedCols.insert(gwi.returnedCols.begin(), gwi.additionalRetCols.begin(), - gwi.additionalRetCols.end()); - - csep->groupByCols(gwi.groupByCols); - csep->orderByCols(gwi.orderByCols); - csep->returnedCols(gwi.returnedCols); - csep->columnMap(gwi.columnMap); - csep->having(havingFilter); - 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 12fa74fa5..5ca94562b 100644 --- a/dbcon/mysql/ha_calpont_impl.cpp +++ b/dbcon/mysql/ha_calpont_impl.cpp @@ -427,7 +427,7 @@ int vbin2hex(const uint8_t* p, const unsigned l, char* o) return 0; } -int fetchNextRow(uchar* buf, cal_table_info& ti, cal_connection_info* ci, bool handler_flag=false) +int fetchNextRow(uchar* buf, cal_table_info& ti, cal_connection_info* ci, bool handler_flag = false) { int rc = HA_ERR_END_OF_FILE; int num_attr = ti.msTablePtr->s->fields; @@ -469,6 +469,7 @@ int fetchNextRow(uchar* buf, cal_table_info& ti, cal_connection_info* ci, bool h { Field** f; f = ti.msTablePtr->field; + //set all fields to null in null col bitmap if (!handler_flag) memset(buf, -1, ti.msTablePtr->s->null_bytes); @@ -476,6 +477,7 @@ int fetchNextRow(uchar* buf, cal_table_info& ti, cal_connection_info* ci, bool h { memset(ti.msTablePtr->null_flags, -1, ti.msTablePtr->s->null_bytes); } + std::vector& colTypes = ti.tpl_scan_ctx->ctp; int64_t intColVal = 0; uint64_t uintColVal = 0; @@ -5074,7 +5076,7 @@ int ha_calpont_impl_rnd_pos(uchar* buf, uchar* pos) return ER_INTERNAL_ERROR; } -/*@brief ha_calpont_impl_group_by_init - Get data for MariaDB group_by +/*@brief ha_calpont_impl_group_by_init - Get data for MariaDB group_by pushdown handler */ /*********************************************************** * DESCRIPTION: @@ -5132,8 +5134,8 @@ int ha_calpont_impl_group_by_init(ha_calpont_group_by_handler* group_hand, 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); csc->identity(CalpontSystemCatalog::FE); @@ -5145,9 +5147,9 @@ 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. + // generated and sent once. if (thd->infinidb_vtable.vtable_state == THD::INFINIDB_DISABLE_VTABLE && !thd->infinidb_vtable.isNewQuery) return 0; @@ -5183,7 +5185,7 @@ int ha_calpont_impl_group_by_init(ha_calpont_group_by_handler* group_hand, TABLE sm::cpsm_conhdl_t* hndl; SCSEP csep; - bool localQuery = (thd->variables.infinidb_local_query > 0 ? true : false); + bool localQuery = (thd->variables.infinidb_local_query > 0 ? true : false); { ci->stats.reset(); // reset query stats @@ -5213,7 +5215,7 @@ int ha_calpont_impl_group_by_init(ha_calpont_group_by_handler* group_hand, TABLE 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; @@ -5256,7 +5258,7 @@ int ha_calpont_impl_group_by_init(ha_calpont_group_by_handler* group_hand, TABLE csep->schemaName(group_hand->table_list->db); csep->traceFlags(ci->traceFlags); - + // MCOL-1052 Send Items lists down to the optimizer. gi.groupByTables = group_hand->table_list; gi.groupByFields = group_hand->select; @@ -5265,7 +5267,7 @@ int ha_calpont_impl_group_by_init(ha_calpont_group_by_handler* group_hand, TABLE gi.groupByOrder = group_hand->order_by; gi.groupByHaving = group_hand->having; gi.groupByDistinct = group_hand->distinct; - + // MCOL-1052 Send pushed conditions here, since server could omit GROUP BY // items in case of = or IN functions used on GROUP BY columns. { @@ -5274,15 +5276,17 @@ int ha_calpont_impl_group_by_init(ha_calpont_group_by_handler* group_hand, TABLE execplan::CalpontSelectExecutionPlan::ColumnMap::iterator condColMapIter; execplan::ParseTree* ptIt; execplan::ReturnedColumn* rcIt; - for(TABLE_LIST* tl = gi.groupByTables; tl; tl=tl->next_local) + + for (TABLE_LIST* tl = gi.groupByTables; tl; tl = tl->next_local) { mapiter = ci->tableMap.find(tl->table); - if(mapiter != ci->tableMap.end() && mapiter->second.condInfo != NULL - && mapiter->second.condInfo->condPush) + + if (mapiter != ci->tableMap.end() && mapiter->second.condInfo != NULL + && mapiter->second.condInfo->condPush) { - while(!mapiter->second.condInfo->ptWorkStack.empty()) + while (!mapiter->second.condInfo->ptWorkStack.empty()) { - ptIt=mapiter->second.condInfo->ptWorkStack.top(); + ptIt = mapiter->second.condInfo->ptWorkStack.top(); mapiter->second.condInfo->ptWorkStack.pop(); gi.pushedPts.push_back(ptIt); } @@ -5316,14 +5320,14 @@ int ha_calpont_impl_group_by_init(ha_calpont_group_by_handler* group_hand, TABLE push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 9999, msg.c_str()); } - #ifdef PLAN_HEX_FILE +#ifdef PLAN_HEX_FILE // plan serialization ifstream ifs("/tmp/li1-plan.hex"); ByteStream bs1; ifs >> bs1; ifs.close(); csep->unserialize(bs1); - #endif +#endif if (ci->traceFlags & 1) { @@ -5338,7 +5342,7 @@ int ha_calpont_impl_group_by_init(ha_calpont_group_by_handler* group_hand, TABLE IDEBUG( cout << "-------------- EXECUTION PLAN END --------------\n" << endl ); } }// end of execution plan generation - + { ByteStream msg; ByteStream emsgBs; @@ -5569,10 +5573,10 @@ internal_error: ci->cal_conn_hndl = 0; } - return ER_INTERNAL_ERROR; + return ER_INTERNAL_ERROR; } -/*@brief ha_calpont_impl_group_by_next - Return result set for MariaDB group_by +/*@brief ha_calpont_impl_group_by_next - Return result set for MariaDB group_by pushdown handler */ /*********************************************************** @@ -5588,7 +5592,7 @@ internal_error: ***********************************************************/ int ha_calpont_impl_group_by_next(ha_calpont_group_by_handler* group_hand, TABLE* table) { - THD* thd = current_thd; + THD* thd = current_thd; /* If this node is the slave, ignore DML to IDB tables */ if (thd->slave_thread && ( @@ -5697,7 +5701,7 @@ int ha_calpont_impl_group_by_next(ha_calpont_group_by_handler* group_hand, TABLE emsg = errorcodes.errorString(rc); } - setError(thd, ER_INTERNAL_ERROR, emsg); + setError(thd, ER_INTERNAL_ERROR, emsg); ci->stats.fErrorNo = rc; CalpontSystemCatalog::removeCalpontSystemCatalog(tid2sid(thd->thread_id)); rc = ER_INTERNAL_ERROR; @@ -5806,7 +5810,7 @@ int ha_calpont_impl_group_by_end(ha_calpont_group_by_handler* group_hand, TABLE* cal_table_info ti = ci->tableMap[table]; sm::cpsm_conhdl_t* hndl; - hndl = ci->cal_conn_hndl; + hndl = ci->cal_conn_hndl; if (ti.tpl_ctx) { diff --git a/dbcon/mysql/ha_calpont_impl_if.h b/dbcon/mysql/ha_calpont_impl_if.h index b1e5ec443..cb603ca49 100644 --- a/dbcon/mysql/ha_calpont_impl_if.h +++ b/dbcon/mysql/ha_calpont_impl_if.h @@ -194,14 +194,14 @@ struct cal_table_info struct cal_group_info { - cal_group_info() : groupByFields(0), + cal_group_info() : groupByFields(0), groupByTables(0), groupByWhere(0), groupByGroup(0), groupByOrder(0), groupByHaving(0), groupByDistinct(false) - { } + { } ~cal_group_info() { } List* groupByFields; // MCOL-1052 SELECT diff --git a/dbcon/mysql/ha_window_function.cpp b/dbcon/mysql/ha_window_function.cpp index 1635c815a..4b648cb15 100644 --- a/dbcon/mysql/ha_window_function.cpp +++ b/dbcon/mysql/ha_window_function.cpp @@ -512,12 +512,13 @@ ReturnedColumn* buildWindowFunctionColumn(Item* item, gp_walk_info& gwi, bool& n { Item* orderItem = *(orderCol->item); srcp.reset(buildReturnedColumn(orderItem, gwi, nonSupport)); - + // MCOL-1052 GROUP BY handler has all of query's agg Items - // as field and correlates them with its extended SELECT Items. + // as field and correlates them with its extended SELECT Items. if (!srcp) { - orderItem = orderCol->item_ptr; + orderItem = orderCol->item_ptr; + if (orderItem) { gwi.fatalParseError = false; diff --git a/dbcon/mysql/is_columnstore_columns.cpp b/dbcon/mysql/is_columnstore_columns.cpp index 31cdb5578..53f67fbbf 100644 --- a/dbcon/mysql/is_columnstore_columns.cpp +++ b/dbcon/mysql/is_columnstore_columns.cpp @@ -27,6 +27,8 @@ #include #include "calpontsystemcatalog.h" #include "dataconvert.h" +#include "exceptclasses.h" +using namespace logging; // Required declaration as it isn't in a MairaDB include @@ -70,7 +72,25 @@ static int is_columnstore_columns_fill(THD* thd, TABLE_LIST* tables, COND* cond) for (std::vector >::const_iterator it = catalog_tables.begin(); it != catalog_tables.end(); ++it) { - execplan::CalpontSystemCatalog::RIDList column_rid_list = systemCatalogPtr->columnRIDs((*it).second, true); + execplan::CalpontSystemCatalog::RIDList column_rid_list; + + // Note a table may get dropped as you iterate over the list of tables. + // So simply ignore the dropped table. + try + { + column_rid_list = systemCatalogPtr->columnRIDs((*it).second, true); + } + catch (IDBExcept& ex) + { + if (ex.errorCode() == ERR_TABLE_NOT_IN_CATALOG) + { + continue; + } + else + { + return 1; + } + } for (size_t col_num = 0; col_num < column_rid_list.size(); col_num++) { diff --git a/dbcon/mysql/sm.cpp b/dbcon/mysql/sm.cpp index fe1a23e76..569fee6a5 100644 --- a/dbcon/mysql/sm.cpp +++ b/dbcon/mysql/sm.cpp @@ -145,7 +145,7 @@ status_t tpl_scan_fetch_getband(cpsm_conhdl_t* hndl, sp_cpsm_tplsch_t& ntplsch, if (ntplsch->bs.length() != 0) { ntplsch->deserializeTable(ntplsch->bs); - + if (ntplsch->rowGroup && ntplsch->rowGroup->getRGData() == NULL) { ntplsch->bs.restart(); diff --git a/oam/install_scripts/syslogSetup.sh b/oam/install_scripts/syslogSetup.sh index 1f4235a30..78b292dac 100755 --- a/oam/install_scripts/syslogSetup.sh +++ b/oam/install_scripts/syslogSetup.sh @@ -13,6 +13,7 @@ syslog_conf=nofile rsyslog7=0 user=`whoami 2>/dev/null` +group=user SUDO=" " if [ "$user" != "root" ]; then @@ -167,9 +168,24 @@ if [ ! -z "$syslog_conf" ] ; then # remove older version incase it was installed by previous build $SUDO rm -rf /etc/rsyslog.d/columnstore.conf + // determine username/groupname + + if [ -f /var/log/messages ]; then + user=`stat -c "%U %G" /var/log/messages | awk '{print $1}'` + group=`stat -c "%U %G" /var/log/messages | awk '{print $2}'` + fi + + if [ -f /var/log/syslog ]; then + user=`stat -c "%U %G" /var/log/syslog | awk '{print $1}'` + group=`stat -c "%U %G" /var/log/syslog | awk '{print $2}'` + fi + + //set permissions + $SUDO chown $user:$group -R /var/log/mariadb > /dev/null 2>&1 + if [ $rsyslog7 == 1 ]; then - sed -i -e s/groupname/adm/g ${columnstoreSyslogFile7} - sed -i -e s/username/syslog/g ${columnstoreSyslogFile7} + sed -i -e s/groupname/$group/g ${columnstoreSyslogFile7} + sed -i -e s/username/$user/g ${columnstoreSyslogFile7} $SUDO rm -f /etc/rsyslog.d/49-columnstore.conf $SUDO cp ${columnstoreSyslogFile7} ${syslog_conf} diff --git a/tools/qfe/bison-win.cpp b/tools/qfe/bison-win.cpp index 7291f6eca..2c1e94a73 100644 --- a/tools/qfe/bison-win.cpp +++ b/tools/qfe/bison-win.cpp @@ -554,9 +554,9 @@ static const yytype_uint8 yydefact[] = static const yytype_int8 yydefgoto[] = { -1, 2, 6, 7, 8, 9, 18, 19, 23, 24, - 25, 33, 36, 10, 11, 52, 39, 45, 46, 48, - 61, 56 -}; + 25, 33, 36, 10, 11, 52, 39, 45, 46, 48, + 61, 56 + }; /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ @@ -576,9 +576,9 @@ static const yytype_int8 yypact[] = static const yytype_int8 yypgoto[] = { -20, -20, -20, 37, -20, 32, 36, -20, -20, -20, - -20, -20, -20, -15, -19, -10, -20, 6, -1, -20, - -20, -20 -}; + -20, -20, -20, -15, -19, -10, -20, 6, -1, -20, + -20, -20 + }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule which diff --git a/utils/rowgroup/rowgroup.cpp b/utils/rowgroup/rowgroup.cpp index 185d3de67..3411f6fa6 100644 --- a/utils/rowgroup/rowgroup.cpp +++ b/utils/rowgroup/rowgroup.cpp @@ -82,10 +82,10 @@ StringStore::~StringStore() #endif } -uint32_t StringStore::storeString(const uint8_t* data, uint32_t len) +uint64_t StringStore::storeString(const uint8_t* data, uint32_t len) { MemChunk* lastMC = NULL; - uint32_t ret = 0; + uint64_t ret = 0; empty = false; // At least a NULL is being stored. @@ -95,7 +95,7 @@ uint32_t StringStore::storeString(const uint8_t* data, uint32_t len) if ((len == 8 || len == 9) && *((uint64_t*) data) == *((uint64_t*) joblist::CPNULLSTRMARK.c_str())) - return numeric_limits::max(); + return numeric_limits::max(); //@bug6065, make StringStore::storeString() thread safe boost::mutex::scoped_lock lk(fMutex, defer_lock); @@ -106,20 +106,21 @@ uint32_t StringStore::storeString(const uint8_t* data, uint32_t len) if (mem.size() > 0) lastMC = (MemChunk*) mem.back().get(); - if (len >= CHUNK_SIZE) + if ((len + 4) >= CHUNK_SIZE) { - shared_array newOne(new uint8_t[len + sizeof(MemChunk)]); + shared_array newOne(new uint8_t[len + sizeof(MemChunk) + 4]); longStrings.push_back(newOne); lastMC = (MemChunk*) longStrings.back().get(); - lastMC->capacity = lastMC->currentSize = len; - memcpy(lastMC->data, data, len); + lastMC->capacity = lastMC->currentSize = len + 4; + memcpy(lastMC->data, &len, 4); + memcpy(lastMC->data + 4, data, len); // High bit to mark a long string - ret = 0x80000000; + ret = 0x8000000000000000; ret += longStrings.size() - 1; } else { - if ((lastMC == NULL) || (lastMC->capacity - lastMC->currentSize < len)) + if ((lastMC == NULL) || (lastMC->capacity - lastMC->currentSize < (len + 4))) { // mem usage debugging //if (lastMC) @@ -134,7 +135,13 @@ uint32_t StringStore::storeString(const uint8_t* data, uint32_t len) ret = ((mem.size() - 1) * CHUNK_SIZE) + lastMC->currentSize; - memcpy(&(lastMC->data[lastMC->currentSize]), data, len); + + // If this ever happens then we have big problems + if (ret & 0x8000000000000000) + throw logic_error("StringStore memory exceeded."); + + memcpy(&(lastMC->data[lastMC->currentSize]), &len, 4); + memcpy(&(lastMC->data[lastMC->currentSize]) + 4, data, len); /* cout << "stored: '" << hex; for (uint32_t i = 0; i < len ; i++) { @@ -142,7 +149,7 @@ uint32_t StringStore::storeString(const uint8_t* data, uint32_t len) } cout << "' at position " << lastMC->currentSize << " len " << len << dec << endl; */ - lastMC->currentSize += len; + lastMC->currentSize += len + 4; } return ret; @@ -150,35 +157,35 @@ uint32_t StringStore::storeString(const uint8_t* data, uint32_t len) void StringStore::serialize(ByteStream& bs) const { - uint32_t i; + uint64_t i; MemChunk* mc; - bs << (uint32_t) mem.size(); + bs << (uint64_t) mem.size(); bs << (uint8_t) empty; for (i = 0; i < mem.size(); i++) { mc = (MemChunk*) mem[i].get(); - bs << (uint32_t) mc->currentSize; + bs << (uint64_t) mc->currentSize; //cout << "serialized " << mc->currentSize << " bytes\n"; bs.append(mc->data, mc->currentSize); } - bs << (uint32_t) longStrings.size(); + bs << (uint64_t) longStrings.size(); for (i = 0; i < longStrings.size(); i++) { mc = (MemChunk*) longStrings[i].get(); - bs << (uint32_t) mc->currentSize; + bs << (uint64_t) mc->currentSize; bs.append(mc->data, mc->currentSize); } } void StringStore::deserialize(ByteStream& bs) { - uint32_t i; - uint32_t count; - uint32_t size; + uint64_t i; + uint64_t count; + uint64_t size; uint8_t* buf; MemChunk* mc; uint8_t tmp8; @@ -856,10 +863,9 @@ bool Row::isNullValue(uint32_t colIndex) const if (inStringTable(colIndex)) { - uint32_t offset, length; - offset = *((uint32_t*) &data[offsets[colIndex]]); - length = *((uint32_t*) &data[offsets[colIndex] + 4]); - return strings->isNullValue(offset, length); + uint64_t offset; + offset = *((uint64_t*) &data[offsets[colIndex]]); + return strings->isNullValue(offset); } if (data[offsets[colIndex]] == 0) // empty string @@ -922,10 +928,9 @@ bool Row::isNullValue(uint32_t colIndex) const if (inStringTable(colIndex)) { - uint32_t offset, length; - offset = *((uint32_t*) &data[pos]); - length = *((uint32_t*) &data[pos + 4]); - return strings->isNullValue(offset, length); + uint64_t offset; + offset = *((uint64_t*) &data[pos]); + return strings->isNullValue(offset); } if (*((uint16_t*) &data[pos]) == 0) @@ -1720,8 +1725,8 @@ RGData RowGroup::duplicate() void Row::setStringField(const std::string& val, uint32_t colIndex) { - uint32_t length; - uint32_t offset; + uint64_t offset; + uint64_t length; //length = strlen(val.c_str()) + 1; length = val.length(); @@ -1732,8 +1737,7 @@ void Row::setStringField(const std::string& val, uint32_t colIndex) if (inStringTable(colIndex)) { offset = strings->storeString((const uint8_t*) val.data(), length); - *((uint32_t*) &data[offsets[colIndex]]) = offset; - *((uint32_t*) &data[offsets[colIndex] + 4]) = length; + *((uint64_t*) &data[offsets[colIndex]]) = offset; // cout << " -- stored offset " << *((uint32_t *) &data[offsets[colIndex]]) // << " length " << *((uint32_t *) &data[offsets[colIndex] + 4]) // << endl; diff --git a/utils/rowgroup/rowgroup.h b/utils/rowgroup/rowgroup.h index 135479918..896da1f4a 100644 --- a/utils/rowgroup/rowgroup.h +++ b/utils/rowgroup/rowgroup.h @@ -92,13 +92,14 @@ public: StringStore(); virtual ~StringStore(); - inline std::string getString(uint32_t offset, uint32_t length) const; - uint32_t storeString(const uint8_t* data, uint32_t length); //returns the offset - inline const uint8_t* getPointer(uint32_t offset) const; + inline std::string getString(uint64_t offset) const; + uint64_t storeString(const uint8_t* data, uint32_t length); //returns the offset + inline const uint8_t* getPointer(uint64_t offset) const; + inline uint32_t getStringLength(uint64_t offset); inline bool isEmpty() const; inline uint64_t getSize() const; - inline bool isNullValue(uint32_t offset, uint32_t length) const; - inline bool equals(const std::string& str, uint32_t offset, uint32_t length) const; + inline bool isNullValue(uint64_t offset) const; + inline bool equals(const std::string& str, uint64_t offset) const; void clear(); @@ -615,9 +616,8 @@ inline bool Row::equals(const std::string& val, uint32_t colIndex) const { if (inStringTable(colIndex)) { - uint32_t offset = *((uint32_t*) &data[offsets[colIndex]]); - uint32_t length = *((uint32_t*) &data[offsets[colIndex] + 4]); - return strings->equals(val, offset, length); + uint64_t offset = *((uint64_t*) &data[offsets[colIndex]]); + return strings->equals(val, offset); } else return (strncmp(val.c_str(), (char*) &data[offsets[colIndex]], getColumnWidth(colIndex)) == 0); @@ -719,7 +719,7 @@ inline int64_t Row::getIntField(uint32_t colIndex) const inline const uint8_t* Row::getStringPointer(uint32_t colIndex) const { if (inStringTable(colIndex)) - return strings->getPointer(*((uint32_t*) &data[offsets[colIndex]])); + return strings->getPointer(*((uint64_t*) &data[offsets[colIndex]])); return &data[offsets[colIndex]]; } @@ -727,14 +727,14 @@ inline const uint8_t* Row::getStringPointer(uint32_t colIndex) const inline uint32_t Row::getStringLength(uint32_t colIndex) const { if (inStringTable(colIndex)) - return *((uint32_t*) &data[offsets[colIndex] + 4]); + return strings->getStringLength(*((uint64_t*) &data[offsets[colIndex]])); return strnlen((char*) &data[offsets[colIndex]], getColumnWidth(colIndex)); } inline void Row::setStringField(const uint8_t* strdata, uint32_t length, uint32_t colIndex) { - uint32_t offset; + uint64_t offset; if (length > getColumnWidth(colIndex)) length = getColumnWidth(colIndex); @@ -742,8 +742,7 @@ inline void Row::setStringField(const uint8_t* strdata, uint32_t length, uint32_ if (inStringTable(colIndex)) { offset = strings->storeString(strdata, length); - *((uint32_t*) &data[offsets[colIndex]]) = offset; - *((uint32_t*) &data[offsets[colIndex] + 4]) = length; + *((uint64_t*) &data[offsets[colIndex]]) = offset; // cout << " -- stored offset " << *((uint32_t *) &data[offsets[colIndex]]) // << " length " << *((uint32_t *) &data[offsets[colIndex] + 4]) // << endl; @@ -759,8 +758,7 @@ inline void Row::setStringField(const uint8_t* strdata, uint32_t length, uint32_ inline std::string Row::getStringField(uint32_t colIndex) const { if (inStringTable(colIndex)) - return strings->getString(*((uint32_t*) &data[offsets[colIndex]]), - *((uint32_t*) &data[offsets[colIndex] + 4])); + return strings->getString(*((uint64_t*) &data[offsets[colIndex]])); // Not all CHAR/VARCHAR are NUL terminated so use length return std::string((char*) &data[offsets[colIndex]], @@ -778,7 +776,7 @@ inline std::string Row::getVarBinaryStringField(uint32_t colIndex) const inline uint32_t Row::getVarBinaryLength(uint32_t colIndex) const { if (inStringTable(colIndex)) - return *((uint32_t*) &data[offsets[colIndex] + 4]); + return strings->getStringLength(*((uint64_t*) &data[offsets[colIndex]]));; return *((uint16_t*) &data[offsets[colIndex]]); } @@ -786,7 +784,7 @@ inline uint32_t Row::getVarBinaryLength(uint32_t colIndex) const inline const uint8_t* Row::getVarBinaryField(uint32_t colIndex) const { if (inStringTable(colIndex)) - return strings->getPointer(*((uint32_t*) &data[offsets[colIndex]])); + return strings->getPointer(*((uint64_t*) &data[offsets[colIndex]])); return &data[offsets[colIndex] + 2]; } @@ -795,7 +793,7 @@ inline const uint8_t* Row::getVarBinaryField(uint32_t& len, uint32_t colIndex) c { if (inStringTable(colIndex)) { - len = *((uint32_t*) &data[offsets[colIndex] + 4]); + len = strings->getStringLength(*((uint64_t*) &data[offsets[colIndex]])); return getVarBinaryField(colIndex); } else @@ -1043,9 +1041,8 @@ inline void Row::setVarBinaryField(const uint8_t* val, uint32_t len, uint32_t co if (inStringTable(colIndex)) { - uint32_t offset = strings->storeString(val, len); - *((uint32_t*) &data[offsets[colIndex]]) = offset; - *((uint32_t*) &data[offsets[colIndex] + 4]) = len; + uint64_t offset = strings->storeString(val, len); + *((uint64_t*) &data[offsets[colIndex]]) = offset; } else { @@ -1762,26 +1759,29 @@ inline void copyRow(const Row& in, Row* out) copyRow(in, out, std::min(in.getColumnCount(), out->getColumnCount())); } -inline std::string StringStore::getString(uint32_t off, uint32_t len) const +inline std::string StringStore::getString(uint64_t off) const { - if (off == std::numeric_limits::max()) + uint32_t length; + + if (off == std::numeric_limits::max()) return joblist::CPNULLSTRMARK; MemChunk* mc; - if (off & 0x80000000) + if (off & 0x8000000000000000) { - off = off - 0x80000000; + off = off - 0x8000000000000000; if (longStrings.size() <= off) return joblist::CPNULLSTRMARK; mc = (MemChunk*) longStrings[off].get(); - return std::string((char*) mc->data, len); + memcpy(&length, mc->data, 4); + return std::string((char*) mc->data + 4, length); } - uint32_t chunk = off / CHUNK_SIZE; - uint32_t offset = off % CHUNK_SIZE; + uint64_t chunk = off / CHUNK_SIZE; + uint64_t offset = off % CHUNK_SIZE; // this has to handle uninitialized data as well. If it's uninitialized it doesn't matter // what gets returned, it just can't go out of bounds. @@ -1790,30 +1790,32 @@ inline std::string StringStore::getString(uint32_t off, uint32_t len) const mc = (MemChunk*) mem[chunk].get(); - if ((offset + len) > mc->currentSize) + memcpy(&length, &mc->data[offset], 4); + + if ((offset + length) > mc->currentSize) return joblist::CPNULLSTRMARK; - return std::string((char*) & (mc->data[offset]), len); + return std::string((char*) & (mc->data[offset]) + 4, length); } -inline const uint8_t* StringStore::getPointer(uint32_t off) const +inline const uint8_t* StringStore::getPointer(uint64_t off) const { - if (off == std::numeric_limits::max()) + if (off == std::numeric_limits::max()) return (const uint8_t*) joblist::CPNULLSTRMARK.c_str(); - uint32_t chunk = off / CHUNK_SIZE; - uint32_t offset = off % CHUNK_SIZE; + uint64_t chunk = off / CHUNK_SIZE; + uint64_t offset = off % CHUNK_SIZE; MemChunk* mc; - if (off & 0x80000000) + if (off & 0x8000000000000000) { - off = off - 0x80000000; + off = off - 0x8000000000000000; if (longStrings.size() <= off) return (const uint8_t*) joblist::CPNULLSTRMARK.c_str(); mc = (MemChunk*) longStrings[off].get(); - return mc->data; + return mc->data + 4; } // this has to handle uninitialized data as well. If it's uninitialized it doesn't matter @@ -1826,19 +1828,18 @@ inline const uint8_t* StringStore::getPointer(uint32_t off) const if (offset > mc->currentSize) return (const uint8_t*) joblist::CPNULLSTRMARK.c_str(); - return &(mc->data[offset]); + return &(mc->data[offset]) + 4; } -inline bool StringStore::isNullValue(uint32_t off, uint32_t len) const +inline bool StringStore::isNullValue(uint64_t off) const { - if (off == std::numeric_limits::max() || len == 0) + uint32_t length; + + if (off == std::numeric_limits::max()) return true; - if (len < 8) - return false; - // Long strings won't be NULL - if (off & 0x80000000) + if (off & 0x8000000000000000) return false; uint32_t chunk = off / CHUNK_SIZE; @@ -1849,35 +1850,46 @@ inline bool StringStore::isNullValue(uint32_t off, uint32_t len) const return true; mc = (MemChunk*) mem[chunk].get(); + memcpy(&length, &mc->data[offset], 4); - if ((offset + len) > mc->currentSize) + if (length == 0) return true; - if (mc->data[offset] == 0) // "" = NULL string for some reason... + if (length < 8) + return false; + + if ((offset + length) > mc->currentSize) return true; - return (*((uint64_t*) &mc->data[offset]) == *((uint64_t*) joblist::CPNULLSTRMARK.c_str())); + if (mc->data[offset + 4] == 0) // "" = NULL string for some reason... + return true; + + return (*((uint64_t*) &mc->data[offset] + 4) == *((uint64_t*) joblist::CPNULLSTRMARK.c_str())); } -inline bool StringStore::equals(const std::string& str, uint32_t off, uint32_t len) const +inline bool StringStore::equals(const std::string& str, uint64_t off) const { - if (off == std::numeric_limits::max() || len == 0) + uint32_t length; + + if (off == std::numeric_limits::max()) return str == joblist::CPNULLSTRMARK; MemChunk* mc; - if (off & 0x80000000) + if (off & 0x8000000000000000) { - if (longStrings.size() <= (off - 0x80000000)) + if (longStrings.size() <= (off - 0x8000000000000000)) return false; - mc = (MemChunk*) longStrings[off - 0x80000000].get(); + mc = (MemChunk*) longStrings[off - 0x8000000000000000].get(); + + memcpy(&length, mc->data, 4); // Not sure if this check it needed, but adds safety - if (len > mc->currentSize) + if (length > mc->currentSize) return false; - return (strncmp(str.c_str(), (const char*) mc->data, len) == 0); + return (strncmp(str.c_str(), (const char*) mc->data + 4, length) == 0); } uint32_t chunk = off / CHUNK_SIZE; @@ -1887,11 +1899,44 @@ inline bool StringStore::equals(const std::string& str, uint32_t off, uint32_t l return false; mc = (MemChunk*) mem[chunk].get(); + memcpy(&length, &mc->data[offset], 4); - if ((offset + len) > mc->currentSize) + if ((offset + length) > mc->currentSize) return false; - return (strncmp(str.c_str(), (const char*) &mc->data[offset], len) == 0); + return (strncmp(str.c_str(), (const char*) &mc->data[offset] + 4, length) == 0); +} +inline uint32_t StringStore::getStringLength(uint64_t off) +{ + uint32_t length; + MemChunk* mc; + + if (off == std::numeric_limits::max()) + return 0; + + if (off & 0x8000000000000000) + { + off = off - 0x8000000000000000; + + if (longStrings.size() <= off) + return 0; + + mc = (MemChunk*) longStrings[off].get(); + memcpy(&length, mc->data, 4); + } + else + { + uint64_t chunk = off / CHUNK_SIZE; + uint64_t offset = off % CHUNK_SIZE; + + if (mem.size() <= chunk) + return 0; + + mc = (MemChunk*) mem[chunk].get(); + memcpy(&length, &mc->data[offset], 4); + } + + return length; } inline bool StringStore::isEmpty() const diff --git a/writeengine/bulk/we_bulkloadbuffer.cpp b/writeengine/bulk/we_bulkloadbuffer.cpp index 506bff2eb..093aec751 100644 --- a/writeengine/bulk/we_bulkloadbuffer.cpp +++ b/writeengine/bulk/we_bulkloadbuffer.cpp @@ -1490,8 +1490,8 @@ int BulkLoadBuffer::parseCol(ColumnInfo& columnInfo) } // create a buffer for the size of the rows being written. - unsigned char* buf = new unsigned char[fTotalReadRowsParser * - columnInfo.column.width]; + unsigned char* buf = new unsigned char[fTotalReadRowsParser* + columnInfo.column.width]; char* field = new char[MAX_FIELD_SIZE + 1]; // Initialize min/max buffer values. We initialize to a sufficient