/* Copyright (C) 2014 InfiniDB, Inc. Copyright (C) 2019 MariaDB Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // $Id: jlf_common.cpp 9655 2013-06-25 23:08:13Z xlou $ #include "calpontsystemcatalog.h" #include "aggregatecolumn.h" #include "pseudocolumn.h" #include "simplecolumn.h" using namespace std; using namespace execplan; #include "messagelog.h" using namespace logging; #include namespace ba = boost::algorithm; #include "dbrm.h" #include "extentmap.h" using namespace BRM; #include "jlf_common.h" using namespace joblist; #include "mcs_decimal.h" namespace { // @brief Returns unique key for a column, table, or expresssion. uint32_t uniqTupleKey(JobInfo& jobInfo, CalpontSystemCatalog::OID& o, CalpontSystemCatalog::OID& t, const string& cn, const string& ca, const string& tn, const string& ta, const string& sn, const string& vw, uint32_t pi, uint64_t en, bool correlated = false) { uint64_t subId = jobInfo.subId; if (correlated && jobInfo.pJobInfo) subId = jobInfo.pJobInfo->subId; string alias(ta); // if (!ca.empty()) // alias += "." + ca; string nm(ta); if (!cn.empty()) nm += "." + cn; UniqId id(o, ta, sn, vw, pi, subId); TupleKeyMap::iterator iter = jobInfo.keyInfo->tupleKeyMap.find(id); if (iter != jobInfo.keyInfo->tupleKeyMap.end()) return iter->second; uint32_t newId = jobInfo.keyInfo->nextKey++; // cout << "new id: " << newId << " -- " << o << ", " << pi << ", " << nm << ", " << vw << ", " << sn << ", // " << subId << endl; jobInfo.keyInfo->tupleKeyMap[id] = newId; jobInfo.keyInfo->tupleKeyVec.push_back(id); jobInfo.keyInfo->tupleKeyToTableOid.insert(make_pair(newId, t)); jobInfo.keyInfo->crossEngine.push_back((en != 0)); string ss = vw; if (ss.length() > 0) ss += "."; if (sn.length() > 0) ss += sn + "."; if (o != t) { string name = cn; if (!ca.empty()) // has an alias name = ca; else if (ta.compare(0, 5, "$sub_") && ta.compare(0, 4, "$exp")) // compare != 0 name = ss + ta + "." + name; jobInfo.keyInfo->tupleKeyToName.push_back(name); jobInfo.keyInfo->keyName.insert(make_pair(newId, cn)); } else { string name = ta; bool useAlias = true; if (name.empty()) { name = tn; useAlias = false; } if (tn.compare(0, 4, "$sub") && tn.compare(0, 4, "$exp")) { if (!useAlias) name = ss + name; } else if (tn.compare(0, 4, "$sub") == 0) { name = "sub-query"; } else { name = "expression"; } jobInfo.keyInfo->tupleKeyToName.push_back(name); jobInfo.keyInfo->keyName.insert(make_pair(newId, tn)); } return newId; } // @brief Returns a suitably fudged column width uint32_t fudgeWidth(const CalpontSystemCatalog::ColType& ict, CalpontSystemCatalog::OID oid) { CalpontSystemCatalog::OID dictOid = isDictCol(ict); CalpontSystemCatalog::ColType ct = ict; if (ct.colDataType != CalpontSystemCatalog::VARBINARY && ct.colDataType != CalpontSystemCatalog::BLOB) { if (ct.colDataType == CalpontSystemCatalog::VARCHAR || ct.colDataType == CalpontSystemCatalog::TEXT) ct.colWidth++; // Round colWidth up if (ct.colWidth == 3) ct.colWidth = 4; else if (ct.colWidth == 5 || ct.colWidth == 6 || ct.colWidth == 7) ct.colWidth = 8; else if (dictOid > 0 && oid != dictOid) // token column ct.colWidth = 8; } else { ct.colWidth += 2; // insert the length bytes } return ct.colWidth; } // @brief Set some tuple info TupleInfo setTupleInfo_(const CalpontSystemCatalog::ColType& ct, CalpontSystemCatalog::OID col_oid, JobInfo& jobInfo, CalpontSystemCatalog::OID tbl_oid, const string& col_name, const string& col_alias, const string& sch_name, const string& tbl_name, const string& tbl_alias, const string& vw_name, bool correlated = false, uint32_t pc_id = 0, uint64_t engine = 0) { // get the unique tupleOids for this column uint32_t tbl_key = uniqTupleKey(jobInfo, tbl_oid, tbl_oid, "", "", tbl_name, tbl_alias, sch_name, vw_name, 0, engine, correlated); uint32_t col_key = uniqTupleKey(jobInfo, col_oid, tbl_oid, col_name, col_alias, tbl_name, tbl_alias, sch_name, vw_name, pc_id, engine, correlated); // If this is the first time we've seen this col, add it to the tim TupleInfoMap::iterator it = jobInfo.keyInfo->tupleInfoMap.find(col_key); TupleInfo ti; if (it != jobInfo.keyInfo->tupleInfoMap.end()) { // We've seen the key ti = it->second; } else { // Haven't even seen the table yet, much less this col ti = TupleInfo(fudgeWidth(ct, col_oid), col_oid, col_key, tbl_key, ct.scale, ct.precision, ct.colDataType, ct.charsetNumber); jobInfo.keyInfo->tupleInfoMap[col_key] = ti; jobInfo.keyInfo->colKeyToTblKey[col_key] = tbl_key; jobInfo.keyInfo->colKeyToTblKey[tbl_key] = tbl_key; jobInfo.keyInfo->colType[col_key] = ct; jobInfo.keyInfo->pseudoType[col_key] = pc_id; } if (pc_id > 0 && jobInfo.pseudoColTable.find(tbl_key) == jobInfo.pseudoColTable.end()) jobInfo.pseudoColTable.insert(tbl_key); return ti; } uint32_t getTupleKey_(const JobInfo& jobInfo, CalpontSystemCatalog::OID oid, const string& colName, const string& tblAlias, const string& schema, const string& view, bool correlated = false, uint32_t pseudo = 0, uint64_t engine = 0) { uint64_t subId = jobInfo.subId; if (correlated && jobInfo.pJobInfo) subId = jobInfo.pJobInfo->subId; string alias(tblAlias); string name(tblAlias); if (!colName.empty()) name += "." + colName; // if (!colAlias.empty()) // alias += "." + colAlias; UniqId id(oid, tblAlias, schema, view, pseudo, subId); TupleKeyMap::const_iterator iter = jobInfo.keyInfo->tupleKeyMap.find(id); if (iter != jobInfo.keyInfo->tupleKeyMap.end()) return iter->second; // dictionaryscan tableOid is 0 in the tuplehashjoin. if (oid != 0) { ostringstream strstm; strstm << "(" << oid << ", "; if (!alias.empty()) strstm << alias; if (!view.empty()) strstm << ", " << view; strstm << ") not found in tuple info map."; Message::Args args; args.add(strstm.str()); jobInfo.logger->logMessage(LOG_TYPE_DEBUG, LogMakeJobList, args, LoggingID(5, jobInfo.sessionId, jobInfo.txnId, 0)); cerr << strstm.str() << endl; // cout << "not found: " << oid << ", " << name << ", " << view << ", " << schema << ", " << subId << // endl; throw logic_error("column is not found in info map."); } return static_cast(-1); } } // namespace namespace joblist { UniqId::UniqId(const execplan::SimpleColumn* sc) : fId(sc->oid()) , // fName(extractTableAlias(sc)+"."+sc->columnName()), fTable(extractTableAlias(sc)) , fSchema(sc->schemaName()) , fView(sc->viewName()) , fPseudo(0) , fSubId(-1) { const PseudoColumn* pc = dynamic_cast(sc); uint32_t pseudoType = (pc) ? pc->pseudoType() : execplan::PSEUDO_UNKNOWN; fPseudo = pseudoType; } UniqId::UniqId(int o, const execplan::SimpleColumn* sc) : fId(o) , // fName(extractTableAlias(sc)+"."+sc->columnName()), fTable(extractTableAlias(sc)) , fSchema(sc->schemaName()) , fView(sc->viewName()) , fPseudo(0) , fSubId(-1) { } string UniqId::toString() const { ostringstream strstm; strstm << fId << ":" << fTable << ":" << fSchema << ":" << fView << ":" << fPseudo << ":" << (int64_t)fSubId; return strstm.str(); } //------------------------------------------------------------------------------ // Returns the table alias for the specified column //------------------------------------------------------------------------------ string extractTableAlias(const SimpleColumn* sc) { return sc->tableAlias(); } //------------------------------------------------------------------------------ // Returns the table alias for the specified column //------------------------------------------------------------------------------ string extractTableAlias(const SSC& sc) { return sc->tableAlias(); } //------------------------------------------------------------------------------ // Returns OID associated with colType if it is a dictionary column, else // the value returned for the OID is 0. //------------------------------------------------------------------------------ CalpontSystemCatalog::OID isDictCol(const CalpontSystemCatalog::ColType& colType) { if (colType.isWideDecimalType()) return 0; if (colType.colWidth > 8) return colType.ddn.dictOID; if (colType.colDataType == CalpontSystemCatalog::VARCHAR && colType.colWidth > 7) return colType.ddn.dictOID; if (colType.colDataType == CalpontSystemCatalog::VARBINARY || colType.colDataType == CalpontSystemCatalog::BLOB || colType.colDataType == CalpontSystemCatalog::TEXT) return colType.ddn.dictOID; return 0; } //------------------------------------------------------------------------------ // Determines if colType is a character column //------------------------------------------------------------------------------ bool isCharCol(const CalpontSystemCatalog::ColType& colType) { switch (colType.colDataType) { case CalpontSystemCatalog::VARCHAR: case CalpontSystemCatalog::CHAR: case CalpontSystemCatalog::BLOB: case CalpontSystemCatalog::TEXT: case CalpontSystemCatalog::CLOB: return true; break; default: return false; break; } return false; } //------------------------------------------------------------------------------ // Returns OID associated with a table //------------------------------------------------------------------------------ CalpontSystemCatalog::OID tableOid(const SimpleColumn* sc, boost::shared_ptr cat) { if (sc->schemaName().empty()) return execplan::CNX_VTABLE_ID; if (sc->isColumnStore() == false) return 0; CalpontSystemCatalog::ROPair p = cat->tableRID(make_table(sc->schemaName(), sc->tableName())); return p.objnum; } uint32_t getTupleKey(JobInfo& jobInfo, const execplan::SimpleColumn* sc, bool add) { int key = -1; const PseudoColumn* pc = dynamic_cast(sc); uint32_t pseudoType = (pc) ? pc->pseudoType() : execplan::PSEUDO_UNKNOWN; if (sc == NULL) { return -1; } if (add) { // setTupleInfo first if add is true, ok if already set. if (sc->schemaName().empty()) { SimpleColumn tmp(*sc, jobInfo.sessionId); tmp.oid(tableOid(sc, jobInfo.csc) + 1 + sc->colPosition()); key = getTupleKey(jobInfo, &tmp); // sub-query should be there } else { CalpontSystemCatalog::ColType ct = sc->colType(); string alias(extractTableAlias(sc)); CalpontSystemCatalog::OID tblOid = tableOid(sc, jobInfo.csc); TupleInfo ti(setTupleInfo(ct, sc->oid(), jobInfo, tblOid, sc, alias)); key = ti.key; CalpontSystemCatalog::OID dictOid = isDictCol(ct); if (dictOid > 0) { ti = setTupleInfo(ct, dictOid, jobInfo, tblOid, sc, alias); jobInfo.keyInfo->dictKeyMap[key] = ti.key; key = ti.key; } } } else { // TupleInfo is expected to be set already return getTupleKey_(jobInfo, sc->oid(), sc->columnName(), extractTableAlias(sc), sc->schemaName(), sc->viewName(), ((sc->joinInfo() & execplan::JOIN_CORRELATED) != 0), pseudoType, (sc->isColumnStore() ? 0 : 1)); } return key; } uint32_t getTupleKey(JobInfo& jobInfo, const SRCP& srcp, bool add) { int key = -1; if (add) { // setTupleInfo first if add is true, ok if already set. const SimpleColumn* sc = dynamic_cast(srcp.get()); if (sc != NULL) { if (sc->schemaName().empty()) { SimpleColumn tmp(*sc, jobInfo.sessionId); tmp.oid(tableOid(sc, jobInfo.csc) + 1 + sc->colPosition()); key = getTupleKey(jobInfo, &tmp); // sub-query should be there } else { CalpontSystemCatalog::ColType ct = sc->colType(); string alias(extractTableAlias(sc)); CalpontSystemCatalog::OID tblOid = tableOid(sc, jobInfo.csc); TupleInfo ti(setTupleInfo(ct, sc->oid(), jobInfo, tblOid, sc, alias)); key = ti.key; CalpontSystemCatalog::OID dictOid = isDictCol(ct); if (dictOid > 0) { ti = setTupleInfo(ct, dictOid, jobInfo, tblOid, sc, alias); jobInfo.keyInfo->dictKeyMap[key] = ti.key; key = ti.key; } } } else { CalpontSystemCatalog::ColType ct = srcp->resultType(); TupleInfo ti(setExpTupleInfo(ct, srcp->expressionId(), srcp->alias(), jobInfo)); key = ti.key; } } else { // TupleInfo is expected to be set already const SimpleColumn* sc = dynamic_cast(srcp.get()); if (sc != NULL) { if (sc->schemaName().empty()) { SimpleColumn tmp(*sc, jobInfo.sessionId); tmp.oid(tableOid(sc, jobInfo.csc) + 1 + sc->colPosition()); key = getTupleKey(jobInfo, &tmp); } else { key = getTupleKey(jobInfo, sc); } // check if this is a dictionary column if (jobInfo.keyInfo->dictKeyMap.find(key) != jobInfo.keyInfo->dictKeyMap.end()) key = jobInfo.keyInfo->dictKeyMap[key]; } else { key = getExpTupleKey(jobInfo, srcp->expressionId()); } } return key; } uint32_t getTableKey(const JobInfo& jobInfo, execplan::CalpontSystemCatalog::OID tableOid, const string& alias, const string& schema, const string& view) { return getTupleKey_(jobInfo, tableOid, "", alias, schema, view); } uint32_t getTableKey(const JobInfo& jobInfo, uint32_t cid) { return jobInfo.keyInfo->colKeyToTblKey[cid]; } void updateTableKey(uint32_t cid, uint32_t tid, JobInfo& jobInfo) { jobInfo.keyInfo->colKeyToTblKey[cid] = tid; } uint32_t getTableKey(JobInfo& jobInfo, JobStep* js) { CalpontSystemCatalog::OID tableOid = js->tableOid(); return getTupleKey_(jobInfo, tableOid, "", js->alias(), js->schema(), js->view()); } uint32_t makeTableKey(JobInfo& jobInfo, const execplan::SimpleColumn* sc) { CalpontSystemCatalog::OID o = tableOid(sc, jobInfo.csc); return uniqTupleKey(jobInfo, o, o, "", "", sc->tableName(), extractTableAlias(sc), sc->schemaName(), sc->viewName(), 0, (sc->isColumnStore() ? 0 : 1), ((sc->joinInfo() & execplan::JOIN_CORRELATED) != 0)); } uint32_t makeTableKey(JobInfo& jobInfo, CalpontSystemCatalog::OID o, const string& tn, const string& ta, const string& sn, const string& vn, uint64_t en) { return uniqTupleKey(jobInfo, o, o, "", "", tn, ta, sn, vn, 0, en); } TupleInfo getTupleInfo(uint32_t columnKey, const JobInfo& jobInfo) { TupleInfoMap::const_iterator cit = jobInfo.keyInfo->tupleInfoMap.find(columnKey); if ((cit == jobInfo.keyInfo->tupleInfoMap.end()) || (cit->second.dtype == CalpontSystemCatalog::BIT)) { ostringstream strstm; strstm << "TupleInfo for (" << jobInfo.keyInfo->tupleKeyVec[columnKey].fId << "," << jobInfo.keyInfo->tupleKeyVec[columnKey].fTable; if (jobInfo.keyInfo->tupleKeyVec[columnKey].fView.length() > 0) strstm << "," << jobInfo.keyInfo->tupleKeyVec[columnKey].fView; strstm << ") could not be found." << endl; cerr << strstm.str(); Message::Args args; args.add(strstm.str()); jobInfo.logger->logMessage(LOG_TYPE_DEBUG, LogMakeJobList, args, LoggingID(5, jobInfo.sessionId, jobInfo.txnId, 0)); throw runtime_error("column's tuple info could not be found"); } return cit->second; } TupleInfo setTupleInfo(const execplan::CalpontSystemCatalog::ColType& ct, execplan::CalpontSystemCatalog::OID col_oid, JobInfo& jobInfo, execplan::CalpontSystemCatalog::OID tbl_oid, const execplan::SimpleColumn* sc, const string& alias) { const PseudoColumn* pc = dynamic_cast(sc); uint32_t pseudoType = (pc) ? pc->pseudoType() : execplan::PSEUDO_UNKNOWN; return setTupleInfo_(ct, col_oid, jobInfo, tbl_oid, sc->columnName(), sc->alias(), sc->schemaName(), sc->tableName(), alias, sc->viewName(), ((sc->joinInfo() & execplan::JOIN_CORRELATED) != 0), pseudoType, (sc->isColumnStore() ? 0 : 1)); } TupleInfo setExpTupleInfo(const execplan::CalpontSystemCatalog::ColType& ct, uint64_t expressionId, const string& alias, JobInfo& jobInfo, bool cr) { // pretend all expressions belong to "virtual" table EXPRESSION, (CNX_EXP_TABLE_ID, expression) // CNX_EXP_TABLE_ID(999) is not for user table or column, there will be no confilict in queries. JobInfo* ji = &jobInfo; if (cr && jobInfo.pJobInfo) ji = jobInfo.pJobInfo; string expAlias("$exp"); if (!(ji->subAlias.empty())) expAlias += ji->subAlias; return setTupleInfo_(ct, expressionId, jobInfo, CNX_EXP_TABLE_ID, "", alias, "", "$exp", expAlias, "", cr); } TupleInfo setExpTupleInfo(const execplan::ReturnedColumn* rc, JobInfo& jobInfo) { return setExpTupleInfo(rc->resultType(), rc->expressionId(), rc->alias(), jobInfo, ((rc->joinInfo() & execplan::JOIN_CORRELATED) != 0)); } uint32_t getExpTupleKey(const JobInfo& jobInfo, uint64_t eid, bool cr) { const JobInfo* ji = &jobInfo; if (cr && jobInfo.pJobInfo) ji = jobInfo.pJobInfo; string expAlias("$exp"); if (!(ji->subAlias.empty())) expAlias += ji->subAlias; return getTupleKey_(jobInfo, eid, "", expAlias, "", "", cr); } void addAggregateColumn(ReturnedColumn* agc, int idx, RetColsVector& vec, JobInfo& jobInfo) { uint32_t eid = agc->expressionId(); setExpTupleInfo(agc->resultType(), eid, agc->alias(), jobInfo); vector >::iterator i; for (i = jobInfo.aggEidIndexList.begin(); i != jobInfo.aggEidIndexList.end(); ++i) { if (i->first == (int)eid) break; } if (idx < 0 && i != jobInfo.aggEidIndexList.end()) { agc->inputIndex(i->second); jobInfo.cloneAggregateColMap.insert(make_pair(vec[i->second].get(), agc)); } else { SRCP srcp; if (idx < 0) { srcp.reset(agc->clone()); idx = vec.size(); vec.push_back(srcp); } else { srcp = vec[idx]; } jobInfo.aggEidIndexList.push_back(make_pair(eid, idx)); agc->inputIndex(idx); jobInfo.cloneAggregateColMap.insert(make_pair(srcp.get(), agc)); } } bool operator<(const struct UniqId& x, const struct UniqId& y) { return ((x.fId < y.fId) || (x.fId == y.fId && x.fTable < y.fTable) || (x.fId == y.fId && x.fTable == y.fTable && x.fSchema < y.fSchema) || (x.fId == y.fId && x.fTable == y.fTable && x.fSchema == y.fSchema && x.fView < y.fView) || (x.fId == y.fId && x.fTable == y.fTable && x.fSchema == y.fSchema && x.fView == y.fView && x.fPseudo < y.fPseudo) || (x.fId == y.fId && x.fTable == y.fTable && x.fSchema == y.fSchema && x.fView == y.fView && x.fPseudo == y.fPseudo && x.fSubId < y.fSubId)); } bool operator==(const struct UniqId& x, const struct UniqId& y) { return (x.fId == y.fId && x.fTable == y.fTable && x.fSchema == y.fSchema && x.fView == y.fView && x.fPseudo == y.fPseudo && x.fSubId == y.fSubId); } void updateDerivedColumn(JobInfo& jobInfo, SimpleColumn* sc, CalpontSystemCatalog::ColType& ct) { sc->oid(tableOid(sc, jobInfo.csc) + 1 + sc->colPosition()); map::iterator i = jobInfo.vtableColTypes.find(UniqId(sc)); if (i != jobInfo.vtableColTypes.end()) ct = i->second; } bool filterWithDictionary(execplan::CalpontSystemCatalog::OID dictOid, uint64_t n) { // if n == 0, no dictionary scan, alway filter with dictionary. if (n == 0) return true; // if n == ulong_max, always use dictionary scan if (n == ULONG_MAX) return false; vector entries; DBRM dbrm; if (dbrm.getExtents(dictOid, entries) != 0) return false; // Just do pdictionaryscan and let job step handle this. vector::iterator it = entries.begin(); bool ret = false; n--; // HWM starts at 0 while (it != entries.end()) { if (it->HWM > n) { ret = true; break; } it++; } return ret; } // @Bug 1230 & 1955 // Don't allow join/compare on "incompatible" cols // Compatible columns: // any 1,2,4,8-byte int to any 1,2,4,8-byte int // decimal w/scale x to decimal w/scale x // date to date // datetime to datetime // string to string bool compatibleColumnTypes(const CalpontSystemCatalog::ColType& ct1, const CalpontSystemCatalog::ColType& ct2, bool forJoin) { return compatibleColumnTypes(ct1.colDataType, ct1.scale, ct2.colDataType, ct2.scale, forJoin); } bool compatibleColumnTypes(const CalpontSystemCatalog::ColDataType& dt1, uint32_t scale1, const CalpontSystemCatalog::ColDataType& dt2, uint32_t scale2, bool forJoin) { // disable VARBINARY used in join if (dt1 == CalpontSystemCatalog::VARBINARY || dt2 == CalpontSystemCatalog::VARBINARY) throw runtime_error("Comparsion between VARBINARY columns is not supported."); switch (dt1) { case CalpontSystemCatalog::BIT: if (dt2 != CalpontSystemCatalog::BIT) return false; break; case CalpontSystemCatalog::TINYINT: case CalpontSystemCatalog::SMALLINT: case CalpontSystemCatalog::MEDINT: case CalpontSystemCatalog::INT: case CalpontSystemCatalog::BIGINT: case CalpontSystemCatalog::DECIMAL: case CalpontSystemCatalog::UTINYINT: case CalpontSystemCatalog::USMALLINT: case CalpontSystemCatalog::UMEDINT: case CalpontSystemCatalog::UINT: case CalpontSystemCatalog::UBIGINT: case CalpontSystemCatalog::UDECIMAL: if (dt2 != CalpontSystemCatalog::TINYINT && dt2 != CalpontSystemCatalog::SMALLINT && dt2 != CalpontSystemCatalog::MEDINT && dt2 != CalpontSystemCatalog::INT && dt2 != CalpontSystemCatalog::BIGINT && dt2 != CalpontSystemCatalog::DECIMAL && dt2 != CalpontSystemCatalog::UTINYINT && dt2 != CalpontSystemCatalog::USMALLINT && dt2 != CalpontSystemCatalog::UMEDINT && dt2 != CalpontSystemCatalog::UINT && dt2 != CalpontSystemCatalog::UBIGINT && dt2 != CalpontSystemCatalog::UDECIMAL) return false; if (scale2 != scale1) return false; break; case CalpontSystemCatalog::DATE: if (dt2 != CalpontSystemCatalog::DATE) return false; break; case CalpontSystemCatalog::DATETIME: if (dt2 != CalpontSystemCatalog::DATETIME) return false; break; case CalpontSystemCatalog::TIMESTAMP: if (dt2 != CalpontSystemCatalog::TIMESTAMP) return false; break; case CalpontSystemCatalog::TIME: if (dt2 != CalpontSystemCatalog::TIME) return false; break; case CalpontSystemCatalog::CHAR: case CalpontSystemCatalog::VARCHAR: case CalpontSystemCatalog::TEXT: // @bug 1495 compound/string join if (dt2 != CalpontSystemCatalog::VARCHAR && dt2 != CalpontSystemCatalog::CHAR && dt2 != CalpontSystemCatalog::TEXT) return false; break; case CalpontSystemCatalog::VARBINARY: case CalpontSystemCatalog::BLOB: if (dt2 != CalpontSystemCatalog::VARBINARY && dt2 != CalpontSystemCatalog::BLOB) return false; break; case CalpontSystemCatalog::FLOAT: case CalpontSystemCatalog::UFLOAT: if (forJoin && (dt2 != CalpontSystemCatalog::FLOAT && dt2 != CalpontSystemCatalog::FLOAT)) return false; else if (dt2 != CalpontSystemCatalog::FLOAT && dt2 != CalpontSystemCatalog::DOUBLE && dt2 != CalpontSystemCatalog::UFLOAT && dt2 != CalpontSystemCatalog::UDOUBLE) return false; break; case CalpontSystemCatalog::DOUBLE: case CalpontSystemCatalog::UDOUBLE: if (forJoin && (dt2 != CalpontSystemCatalog::DOUBLE && dt2 != CalpontSystemCatalog::UDOUBLE)) return false; else if (dt2 != CalpontSystemCatalog::FLOAT && dt2 != CalpontSystemCatalog::DOUBLE && dt2 != CalpontSystemCatalog::UFLOAT && dt2 != CalpontSystemCatalog::UDOUBLE) return false; break; case CalpontSystemCatalog::LONGDOUBLE: if (forJoin && (dt2 != CalpontSystemCatalog::LONGDOUBLE)) return false; else if (dt2 != CalpontSystemCatalog::FLOAT && dt2 != CalpontSystemCatalog::DOUBLE && dt2 != CalpontSystemCatalog::UFLOAT && dt2 != CalpontSystemCatalog::UDOUBLE && dt2 != CalpontSystemCatalog::LONGDOUBLE) return false; break; default: return false; break; } return true; } } // namespace joblist